歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android Fragment 你應該知道的一切

前面寫過兩篇Android Fragment的介紹,主要就是介紹其功能:Android Fragment 真正的完全解析(上)和Android Fragment 真正的完全解析(下) 有興趣的可以湊合看下(見 )。之前的文章屬於怎麼使用Fragment,本文目標教你如何用好Fragment,即Fragment的一些使用的建議,(多數內容來自:android programming the big nerd ranch guide 一書,直接百度,你懂的,雖然是基礎書籍,還是很值得一看的)。

本文相關源碼下載地址

------------------------------------------分割線------------------------------------------

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2015年資料/8月/8日/Android Fragment 你應該知道的一切/

下載方法見 http://www.linuxidc.com/Linux/2013-07/87684.htm

------------------------------------------分割線------------------------------------------

1、概述

首先我們簡單回顧一下,相信大家對Fragment的都不陌生,對於Fragment的使用,一方面Activity需要在布局中為Fragment安排位置,另一方面需要管理好Fragment的生命周期。Activity中有個FragmentManager,其內部維護fragment隊列,以及fragment事務的回退棧。

一般情況下,我們在Activity裡面會這麼添加Fragment:

public class MainActivity extends FragmentActivity
{
 
 private ContentFragment mContentFragment  ;

 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 
  FragmentManager fm = getSupportFragmentManager();
  mContentFragment = (ContentFragment) fm.findFragmentById(R.id.id_fragment_container);
 
  if(mContentFragment == null )
  {
   mContentFragment = new ContentFragment();
   fm.beginTransaction().add(R.id.id_fragment_container,mContentFragment).commit();
  }

 }

}

針對上面代碼,問兩個問題:

1、為什麼需要判null呢?

主要是因為,當Activity因為配置發生改變(屏幕旋轉)或者內存不足被系統殺死,造成重新創建時,我們的fragment會被保存下來,但是會創建新的FragmentManager,新的FragmentManager會首先會去獲取保存下來的fragment隊列,重建fragment隊列,從而恢復之前的狀態。

2、add(R.id.id_fragment_container,mContentFragment)中的布局的id有何作用?

一方面呢,是告知FragmentManager,此fragment的位置;另一方面是此fragment的唯一標識;就像我們上面通過fm.findFragmentById(R.id.id_fragment_container)查找~~

好了,簡單回顧了一下基本用法,具體的還請參考上面的博客或者其他資料,接下來,介紹一些使用的意見~~

2、Fragment Arguments

下面描述一個簡單的場景,比如我們某個按鈕觸發Activity跳轉,需要通過Intent傳遞參數到目標Activity的Fragment中,那麼此Fragment如何獲取當前的Intent的值呢?

有哥們會說,這個簡單?看我的代碼(問題代碼):

public class ContentFragment extends Fragment
{
 
 private String mArgument ;
 public static final String ARGUMENT ="argument";
 @Override
 public void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
 
  mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
 
 }

我們直接在Fragment的onCreate中,拿到宿主Activty,宿主Activity中肯定能通過getIntent拿到Intent,然後通過get方法,隨意拿參數~~

這麼寫,功能上是實現了,但是呢?存在一個大問題:我們用Fragment的一個很大的原因,就是為了復用。你這麼寫,相當於這個Fragment已經完全和當前這個宿主Activity綁定了,復用直接廢了~~~所以呢?我們換種方式,推薦使用arguments來創建Fragment。

public class ContentFragment extends Fragment
{

 private String mArgument;
 public static final String ARGUMENT = "argument";

 @Override
 public void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  // mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
  Bundle bundle = getArguments();
  if (bundle != null)
   mArgument = bundle.getString(ARGUMENT);

 }

 /**
  * 傳入需要的參數,設置給arguments
  * @param argument
  * @return
  */
 public static ContentFragment newInstance(String argument)
 {
  Bundle bundle = new Bundle();
  bundle.putString(ARGUMENT, argument);
  ContentFragment contentFragment = new ContentFragment();
  contentFragment.setArguments(bundle);
  return contentFragment;
 }

給Fragment添加newInstance方法,將需要的參數傳入,設置到bundle中,然後setArguments(bundle),最後在onCreate中進行獲取;

這樣就完成了Fragment和Activity間的解耦。當然了這裡需要注意:

setArguments方法必須在fragment創建以後,添加給Activity前完成。千萬不要,首先調用了add,然後設置arguments。

3、Fragment的startActivityForResult

依舊是一個簡單的場景:兩個Fragment,一個展示文章列表的Fragment(叫做ListTitleFragment),一個顯示詳細信息的Fragment(叫做:ContentFragment),當然了,這兩個Fragment都有其宿主Activity。

現在,我們點擊列表Fragment中的列表項,傳入相應的參數,去詳細信息的Fragment展示詳細的信息,在詳細信息頁面,用戶可以進行點評,當用戶點擊back以後,我們以往點評結果顯示在列表的Fragment對於的列表項中;

也就是說,我們點擊跳轉到對應Activity的Fragment中,並且希望它能夠返回參數,那麼我們肯定是使用Fragment.startActivityForResult ;

在Fragment中存在startActivityForResult()以及onActivityResult()方法,但是呢,沒有setResult()方法,用於設置返回的intent,這樣我們就需要通過調用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);。

詳細代碼:

ListTitleFragment

public class ListTitleFragment extends ListFragment
{

 public static final int REQUEST_DETAIL = 0x110;
 private List<String> mTitles = Arrays.asList("Hello", "World", "Android");
 private int mCurrentPos ;
 private ArrayAdapter<String> mAdapter ;

 
 @Override
 public void onActivityCreated(Bundle savedInstanceState)
 {
  super.onActivityCreated(savedInstanceState);
  setListAdapter(mAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mTitles));
 }
 
 @Override
 public void onListItemClick(ListView l, View v, int position, long id)
 {
  mCurrentPos = position ;
  Intent intent = new Intent(getActivity(),ContentActivity.class);
  intent.putExtra(ContentFragment.ARGUMENT, mTitles.get(position));
  startActivityForResult(intent, REQUEST_DETAIL);
 }

 
 @Override
 public void onActivityResult(int requestCode, int resultCode, Intent data)
 {
  Log.e("TAG", "onActivityResult");
  super.onActivityResult(requestCode, resultCode, data);
  if(requestCode == REQUEST_DETAIL)
  {
   mTitles.set(mCurrentPos, mTitles.get(mCurrentPos)+" -- "+data.getStringExtra(ContentFragment.RESPONSE));
   mAdapter.notifyDataSetChanged();
  }
 }
}

ContentFragment

public class ContentFragment extends Fragment
{

 private String mArgument;
 public static final String ARGUMENT = "argument";
 public static final String RESPONSE = "response";

 @Override
 public void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  Bundle bundle = getArguments();
  if (bundle != null)
  {
   mArgument = bundle.getString(ARGUMENT);
   Intent intent = new Intent();
   intent.putExtra(RESPONSE, "good");
   getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);
  }

 }

 public static ContentFragment newInstance(String argument)
 {
  Bundle bundle = new Bundle();
  bundle.putString(ARGUMENT, argument);
  ContentFragment contentFragment = new ContentFragment();
  contentFragment.setArguments(bundle);
  return contentFragment;
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState)
 {
  Random random = new Random();
  TextView tv = new TextView(getActivity());
  tv.setText(mArgument);
  tv.setGravity(Gravity.CENTER);
  tv.setBackgroundColor(Color.argb(random.nextInt(100),
    random.nextInt(255), random.nextInt(255), random.nextInt(255)));
  return tv;
 }
}

貼出了兩個Fragment的代碼,可以看到我們在ListTitleFragment.onListItemClick,使用startActivityForResult()跳轉到目標Activity,在目標Activity的Fragment(ContentFragment)中獲取參數,然後調用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);進行設置返回的數據;最後在ListTitleFragment.onActivityResult()拿到返回的數據進行回顯;
為大家以後在遇到類似問題時,提供了解決方案;也說明了一個問題:fragment能夠從Activity中接收返回結果,但是其自設無法產生返回結果,只有Activity擁有返回結果。

接下來我要貼一下,這兩個Fragment的宿主Activity:

ListTitleActivity

public class ListTitleActivity extends FragmentActivity
{

 private ListTitleFragment mListFragment;

 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_single_fragment);
 
  FragmentManager fm = getSupportFragmentManager();
  mListFragment = (ListTitleFragment) fm.findFragmentById(R.id.id_fragment_container);
 
  if(mListFragment == null )
  {
   mListFragment = new ListTitleFragment();
   fm.beginTransaction().add(R.id.id_fragment_container,mListFragment).commit();
  }

 }
}

ContentActivity:

public class ContentActivity extends FragmentActivity
{

 private ContentFragment mContentFragment;

 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_single_fragment);
 
  FragmentManager fm = getSupportFragmentManager();
  mContentFragment = (ContentFragment) fm.findFragmentById(R.id.id_fragment_container);
 
  if(mContentFragment == null )
  {
   String title = getIntent().getStringExtra(ContentFragment.ARGUMENT);
   mContentFragment = ContentFragment.newInstance(title);
   fm.beginTransaction().add(R.id.id_fragment_container,mContentFragment).commit();
  }

 }
}

有沒有發現兩個Activity中的代碼極其的類似,且使用了同一個布局文件:

activity_single_fragment.xml

<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:id="@+id/id_fragment_container"
>


</RelativeLayout>

為什麼要貼這Acticity的代碼呢?因為我們項目中,如果原則上使用Fragment,會發現大量類似的代碼,那麼我們就可以抽象一個Activity出來,托管我們的Single Fragment。

詳細見下一節。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-08/121314p2.htm

Copyright © Linux教程網 All Rights Reserved