歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android Fragment 你應該知道的一切

Android Fragment 你應該知道的一切

日期:2017/3/1 9:26:30   编辑:Linux編程

前面寫過兩篇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