首先感謝KingJA提供的第三方庫(kù)LoadSir,項(xiàng)目地址為:https://github.com/KingJA/LoadSir
LoadSir是一個(gè)高效易用,低碳環(huán)保,擴(kuò)展性良好的加載反饋?lái)?yè)管理框架,在加載網(wǎng)絡(luò)或其他數(shù)據(jù)時(shí)候,根據(jù)需求切換狀態(tài)頁(yè)面, 可添加自定義狀態(tài)頁(yè)面,如加載中,加載失敗,無(wú)數(shù)據(jù),網(wǎng)絡(luò)超時(shí),如占位圖,登錄失效等常用頁(yè)面??膳浜暇W(wǎng)絡(luò)加載框架,結(jié)合返回 狀態(tài)碼,錯(cuò)誤碼,數(shù)據(jù)進(jìn)行狀態(tài)頁(yè)自動(dòng)切換,封裝使用效果更佳。
LoadSir的功能及特點(diǎn)
支持Activity,F(xiàn)ragment,F(xiàn)ragment(v4),View狀態(tài)回調(diào)
適配多個(gè)Fragment切換,及Fragment+ViewPager切換,不會(huì)布局疊加或者布局錯(cuò)亂
利用泛型轉(zhuǎn)換輸入信號(hào)和輸出狀態(tài),可根據(jù)網(wǎng)絡(luò)返回體的狀態(tài)碼或者數(shù)據(jù)返回自動(dòng)適配狀態(tài)頁(yè),實(shí)現(xiàn)全局自動(dòng)狀態(tài)切換
無(wú)需修改布局文件
只加載唯一一個(gè)狀態(tài)視圖,不會(huì)預(yù)加載全部視圖
大致效果如下:

不需要設(shè)置枚舉或者常量狀態(tài)值,直接用狀態(tài)頁(yè)類類型(xxx.class)作為狀態(tài)碼
可對(duì)單個(gè)狀態(tài)頁(yè)單獨(dú)設(shè)置點(diǎn)擊事件,根據(jù)返回boolean值覆蓋或者結(jié)合OnReloadListener使用,如網(wǎng)絡(luò)錯(cuò)誤可跳轉(zhuǎn)設(shè)置頁(yè)
無(wú)預(yù)設(shè)頁(yè)面,低耦合,開(kāi)發(fā)者隨心配置
可保留標(biāo)題欄(Toolbar,titile view等)
可設(shè)置重新加載點(diǎn)擊事件(OnReloadListener)
可自定義狀態(tài)頁(yè)(繼承Callback類)
可在子線程直接切換狀態(tài)
可設(shè)置初始狀態(tài)頁(yè)(常用進(jìn)度頁(yè)作為初始狀態(tài))
可擴(kuò)展?fàn)顟B(tài)頁(yè)面,在配置中添加自定義狀態(tài)頁(yè)
可全局單例配置,也可以單獨(dú)配置
首先我們需要在項(xiàng)目中添加相關(guān)依賴:compile'com.kingja.loadsir:loadsir:1.2.2

第一步:配置
全局配置方式
全局配置方式,使用的是單例模式,即獲取的配置都是一樣的??稍贏pplication中配置,添加狀態(tài)頁(yè),設(shè)置默認(rèn)狀態(tài)頁(yè)
public class MyApp extends Application{
@Override
public void onCreate() {
super.onCreate();
LoadSir.beginBuilder().addCallback(new ErrorCallback())
.addCallback(new EmptyCallback())
.addCallback(new LoadingCallback())
.addCallback(new TimeoutCallback())
.addCallback(new CustomCallback())
.setDefaultCallback(LoadingCallback.class)
.commit();
}}
單獨(dú)配置方式
如果你即想保留全局配置,又想在某個(gè)特殊頁(yè)面加點(diǎn)不同的配置,可采用該方式。
LoadSir loadSir = new LoadSir.Builder()
.addCallback(new LoadingCallback())
.addCallback(new EmptyCallback())
.addCallback(new ErrorCallback())
.build();
loadService = loadSir.register(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加載邏輯
}
});
第二步:注冊(cè)
在Activity中使用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content);
// Your can change the callback on sub thread directly.
LoadService loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
// 重新加載邏輯
}
});}}

這里需要注意,register中有兩個(gè)參數(shù),這里看第一個(gè)參數(shù),第一個(gè)為Object,通常我們這里是我們要展示狀態(tài)視圖的View。

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(setLayoutId(), container, false);
initView();
mBaseLoadService = LoadSir.getDefault().register(mRootView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
onNetReload(v);
}
});
return mBaseLoadService.getLoadLayout();
}
當(dāng)然,我們也可以是指定的某個(gè)View,假設(shè)在Fragment中只有某個(gè)控件是需要獲取數(shù)據(jù),并且該控件并沒(méi)有占滿整個(gè)布局,那么我們也可以把第一個(gè)參數(shù)設(shè)置為指定的控件。
ImageView imageView = (ImageView) findViewById(R.id.iv_img);
LoadSir loadSir = new LoadSir.Builder()
.addCallback(new TimeoutCallback())
.setDefaultCallback(LoadingCallback.class)
.build();
loadService = loadSir.register(imageView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
loadService.showCallback(LoadingCallback.class);
// 重新加載邏輯
}});
使用還是非常簡(jiǎn)單的,這里需要注意,我們所有的CallBack都是自定義的,所有的狀態(tài)視圖都由我們自己來(lái)定義,只需要繼承CallBack,重寫onCreateView方法即可。
加載中callBack
public class LoadingCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_loading }}
超時(shí)CallBack
public class TimeoutCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_timeout;
}
@Override
protected boolean onRetry(Context context, View view) {
Toast.makeText(context.getApplicationContext(),"Connecting to the network again!",Toast.LENGTH_SHORT).show();
return false;
}}
出錯(cuò)callBack
public class ErrorCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_error;
}}
無(wú)數(shù)據(jù)CallBack:
public class EmptyCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_empty;
}}
自定義CallBack:
public class CustomCallback extends Callback {
@Override
protected int onCreateView() {
return R.layout.layout_custom;
}
@Override
protected boolean onRetry(final Context context, View view) {
Toast.makeText(context.getApplicationContext(), "Hello buddy, how r u! :p", Toast.LENGTH_SHORT).show();
(view.findViewById(R.id.iv_gift)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context.getApplicationContext(), "It's your gift! :p", Toast.LENGTH_SHORT).show();
}
});
return true;
}}
知道了如何使用LoadSir之后,我們就要將它構(gòu)建到我們的基類BaseFragment當(dāng)中了。
為了避免重復(fù)創(chuàng)建Fragment,以及數(shù)據(jù)的重復(fù)加載,我們通常會(huì)使用懶加載方式來(lái)解決這一問(wèn)題。這里我就直接貼代碼了,注釋得非常清楚,無(wú)非就是判斷當(dāng)然Fragment是否可見(jiàn),可見(jiàn)的話并且是第一次才加載數(shù)據(jù)。
public abstract class BaseFragment extends Fragment{
public Context mContext;
protected View mRootView;
protected LoadService mBaseLoadService;
/**
* 是否為可見(jiàn)狀態(tài)
*/
private boolean isVisible;
/**
* 是否視圖加載完成(第一次加載)
*/
private boolean isPrepared;
/**
* Fragment生命周期中,在執(zhí)行完onAttach之后就可以獲取到上下文了
* @param savedInstanceState
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(setLayoutId(), container, false);
initView();
mBaseLoadService = LoadSir.getDefault().register(mRootView, new Callback.OnReloadListener() {
@Override
public void onReload(View v) {
onNetReload(v);
}
});
return mBaseLoadService.getLoadLayout();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
isPrepared = true;
lazyLoad();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//如果可見(jiàn)
if (getUserVisibleHint()){
isVisible = true;
onVisible();
}else {
isVisible = false;
onInvisible();
}
}
/**
*可見(jiàn)做懶加載
*/
private void onVisible(){
lazyLoad();
}
private void lazyLoad(){
if (!isVisible || !isPrepared){
return;
}
initData();
isPrepared = false;
}
/**
* 不可見(jiàn)時(shí)做一些銷毀操作
*/
protected void onInvisible(){}
/**
* 初始化控件
*/
public abstract void initView();
/**
* 綁定布局
*/
protected abstract int setLayoutId();
/**
* 初始化數(shù)據(jù)
*/
protected abstract void initData();
/**
* 重新加載
* @param v
*/
protected abstract void onNetReload(View v);}
基類還是非常簡(jiǎn)單的,我們可以根據(jù)自己的業(yè)務(wù)需求自行拓展,比如加入Toast等。
那么我們Fragment中的代碼就非常簡(jiǎn)單了,為了更好的展示效果,我們?cè)诔跏蓟瘮?shù)據(jù)時(shí),模擬網(wǎng)絡(luò)請(qǐng)求失敗,在onNetReload方法中模擬請(qǐng)求成功。
public class OneFragment extends BaseFragment {
@Override
public void initView() {
}
@Override
protected int setLayoutId() {
return R.layout.view1;
}
@Override
protected void initData() {
PostUtil.postCallbackDelayed(mBaseLoadService, ErrorCallback.class);
}
@Override
protected void onNetReload(View v) {
Toast.makeText(getContext(),"reload in Fragment A",Toast.LENGTH_SHORT).show();
mBaseLoadService.showCallback(LoadingCallback.class);
PostUtil.postSuccessDelayed(mBaseLoadService);
}}

本文到此基本可以結(jié)束了,畢竟標(biāo)題是BaseFragment,再說(shuō)就跑題了?。?!至于TabLayoyut和ViewPager結(jié)合Fragment的使用我這里就不介紹了。
這里把文章中設(shè)計(jì)到的一些資源文件放出來(lái)給大家。




