Fragment與Activity。什么時(shí)候用什么時(shí)候不用?
回答: 看需求!
個(gè)人覺(jué)得推薦場(chǎng)景:
(使用Fragment完全替換Activity,而Activity用來(lái)管理Fragment或者把fragment當(dāng)作一個(gè)輕量級(jí)activity使用)
當(dāng)你一個(gè)Activity需要模塊化的時(shí)候,你可以單獨(dú)寫(xiě)一個(gè)Fragment并且嵌套在任何一個(gè)界面,不用擔(dān)心重復(fù)代碼。
一般主頁(yè)的每個(gè)tab都是用Fragment,類(lèi)似的一個(gè)頁(yè)面下有多個(gè)布局需要切換的時(shí)候感覺(jué)用Fragment很方便
布局在不同的設(shè)備上比如手機(jī)和平板上的適配
比如 App 中有一個(gè)新用戶(hù)注冊(cè)功能,包括設(shè)置用戶(hù)名、密碼、手機(jī)號(hào)等等流程,設(shè)計(jì)師在 UI 設(shè)計(jì)上將每個(gè)流程單獨(dú)設(shè)計(jì)成一個(gè)界面,引導(dǎo)用戶(hù)一步步操作。作為開(kāi)發(fā)人員,如果將每一個(gè)完善信息的流程單獨(dú)設(shè)置成一個(gè) Activity 的話(huà)操作起來(lái)就比較繁瑣,并且也不易于應(yīng)用里的邏輯處理,而如果使用 Fragment 并結(jié)合回退棧的話(huà),就非常合適了
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.hide(firstStepFragment);
if (secondStepFragment==null){
ft.add(R.id.fl_content, secondStepFragment);
}else {
ft.show(secondStepFragment);
}
ft.addToBackStack(null);
ft.commit();
注意:這里使用了 hide() 方法,而不是 replace() 方法,因?yàn)槲覀儺?dāng)然希望用戶(hù)返回上一步操作時(shí),之前設(shè)置的內(nèi)容不會(huì)消失。
Activity管理Fragment的思路:(曾經(jīng)用過(guò))
當(dāng)然別忘了FragmentManager。管理著 正在activity里顯示的fragment們(用list)以及detach之后跟view hiearchy斷開(kāi)聯(lián)系的被放進(jìn)backstack的fragment:
建一個(gè)hashmap,用于存放已實(shí)例過(guò)的fragment,要復(fù)用的時(shí)候直接拿出來(lái),而且還可以解決Fragment 重疊問(wèn)題;
-
寫(xiě)一個(gè)Basefragment,子Fragment繼承與它,自定義接口,在activity里實(shí)現(xiàn)接口方法,因此activity可以根據(jù)待實(shí)例化fragment的屬性進(jìn)行管理控制。(這也是觀(guān)察著模式)
具體實(shí)現(xiàn)方式如下:
public class BaseFragment extends Fragment implements View.OnClickListener{
public interface IOneFragmentClickListener{
void onOneFragmentClick();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_one, null);
contentView.findViewById(R.id.edt_one).setOnClickListener(this);
return contentView;
}
@Override
public void onClick(View v) {
if (getActivity() instanceof IOneFragmentClickListener){
((IOneFragmentClickListener) getActivity()).onOneFragmentClick();
}
}
}
只要在宿主 Activity 實(shí)現(xiàn) Fragment 定義的對(duì)外接口 IOneFragmentClickListener,便可以實(shí)現(xiàn) Fragment 調(diào)用 Activity 的功能。
fragment的使用:
作為 Activity 界面的一部分,F(xiàn)ragment 的存在必須依附于 Activity,并且與 Activity 一樣,擁有自己的生命周期,同時(shí)處理用戶(hù)的交互動(dòng)作。同一個(gè) Activity 可以有一個(gè)或多個(gè) Fragment 作為界面內(nèi)容,并且可以動(dòng)態(tài)添加、刪除 Fragment,靈活控制 UI 內(nèi)容,也可以用來(lái)解決部分屏幕適配問(wèn)題。
另外,support v4 包中也提供了 Fragment,兼容 Android 3.0 之前的系統(tǒng)(當(dāng)然,現(xiàn)在 3.0 之前的系統(tǒng)在市場(chǎng)上已經(jīng)很少見(jiàn)了,可以不予考慮),使用兼容包需要注意兩點(diǎn):
Activity 必須繼承自 FragmentActivity;
使用 getSupportFragmentManager() 方法獲取 FragmentManager 對(duì)象;
fragment 生命周期:
一邊看一邊提出一些問(wèn)題:
- attach跟add怎么理解?inflate呢?
- attach有什么作用?有什么好處,因此適合什么場(chǎng)景?

個(gè)人對(duì)提出問(wèn)題的回復(fù):
Applications should generally not implement a constructor. Prefer
{@link #onAttach(Context)} instead. It is the first place application code can run where
the fragment is ready to be used - the point where the fragment is actually associated with its context. Some applications may also want to implement {@link #onInflate} to retrieve
attributes from a layout resource, although note this happens when the fragment is attached.</pre>
- attach:將fragment與Activirty聯(lián)系起來(lái),通過(guò)context。所以通過(guò)fragment startActiviotyForResult 其實(shí)也是Activity start的,回調(diào)onActivityResult() 也是應(yīng)該由activity處理。 </pre>
- add:將fragment加到ViewHiearchy中,通過(guò)把fragment加到manager管理的active的fragment的List里。
- onInflate():保存布局里的屬性
Called when a fragment is being created as part of a view layout
inflation, typically from setting the content view of an activity. This may be called immediately after the fragment is created from a <fragment>
tag in a layout file. Note this is <em>before</em> the fragment's
{@link #onAttach(Activity)} has been called; all you should do here is
parse the attributes and save them away. <p>This is called every time the fragment is inflated, even if it is
being inflated into a new instance with saved state. It typically makes sense to re-parse the parameters each time, to allow them to change with different configurations.</p> </pre>
attach與detach及回退棧的配合,如果當(dāng)你detach fragment時(shí),那么被移除的fragment就被停止了(沒(méi)有消亡,但視圖已經(jīng)銷(xiāo)毀了),如果用戶(hù)導(dǎo)航回來(lái)重新加載這個(gè)fragment,它將會(huì)重新啟動(dòng),視圖也會(huì)重新創(chuàng)建,如果你沒(méi)有把事務(wù)加入到堆棧中,當(dāng)fragment被remove時(shí),這個(gè)fragment也就消亡了。
通信方式
通常,F(xiàn)ragment 與 Activity 通信存在三種情形:
-
Activity 操作內(nèi)嵌的 Fragment
由于 Activity 持有所有內(nèi)嵌的 Fragment 對(duì)象實(shí)例(創(chuàng)建實(shí)例時(shí)保存的 Fragment 對(duì)象,或者通過(guò) FragmentManager 類(lèi)提 供的 findFragmentById() 和 findFragmentByTag() 方法也能獲取到 Fragment 對(duì)象),所以可以直接操作 Fragment;
Fragment 操作宿主 Activity;
Fragment 通過(guò)getActivity()方法可以獲取到宿主 Activity 對(duì)象(強(qiáng)制轉(zhuǎn)換類(lèi)型即可),進(jìn)而可以操作宿主 Activity;那么很自然的,獲取到宿主 Activity 對(duì)象的 Fragment 便可以操作其他 Fragment 對(duì)象。Fragment 操作同屬 Activity中的其他 Fragment。
高內(nèi)聚,低耦合。Fragment 做好自己的事情即可,所有涉及到 Fragment 之間的控制顯示等操作,都應(yīng)交由宿主 Activity來(lái)統(tǒng)一管理。
