首先感謝KingJA提供的第三方庫LoadSir,項(xiàng)目地址為:https://github.com/KingJA/LoadSir
LoadSir是一個(gè)高效易用沦补,低碳環(huán)保啊央,擴(kuò)展性良好的加載反饋頁管理框架,在加載網(wǎng)絡(luò)或其他數(shù)據(jù)時(shí)候衍锚,根據(jù)需求切換狀態(tài)頁面, 可添加自定義狀態(tài)頁面嗤堰,如加載中戴质,加載失敗,無數(shù)據(jù)梁棠,網(wǎng)絡(luò)超時(shí)置森,如占位圖,登錄失效等常用頁面符糊≠旌#可配合網(wǎng)絡(luò)加載框架,結(jié)合返回 狀態(tài)碼男娄,錯(cuò)誤碼行贪,數(shù)據(jù)進(jìn)行狀態(tài)頁自動(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)頁橄浓,實(shí)現(xiàn)全局自動(dòng)狀態(tài)切換
無需修改布局文件
只加載唯一一個(gè)狀態(tài)視圖粒梦,不會(huì)預(yù)加載全部視圖
大致效果如下:
不需要設(shè)置枚舉或者常量狀態(tài)值,直接用狀態(tài)頁類類型(xxx.class)作為狀態(tài)碼
可對(duì)單個(gè)狀態(tài)頁單獨(dú)設(shè)置點(diǎn)擊事件荸实,根據(jù)返回boolean值覆蓋或者結(jié)合OnReloadListener使用匀们,如網(wǎng)絡(luò)錯(cuò)誤可跳轉(zhuǎn)設(shè)置頁
無預(yù)設(shè)頁面,低耦合准给,開發(fā)者隨心配置
可保留標(biāo)題欄(Toolbar,titile view等)
可設(shè)置重新加載點(diǎn)擊事件(OnReloadListener)
可自定義狀態(tài)頁(繼承Callback類)
可在子線程直接切換狀態(tài)
可設(shè)置初始狀態(tài)頁(常用進(jìn)度頁作為初始狀態(tài))
可擴(kuò)展?fàn)顟B(tài)頁面泄朴,在配置中添加自定義狀態(tài)頁
可全局單例配置,也可以單獨(dú)配置
首先我們需要在項(xiàng)目中添加相關(guān)依賴:compile'com.kingja.loadsir:loadsir:1.2.2
第一步:配置
全局配置方式
全局配置方式露氮,使用的是單例模式祖灰,即獲取的配置都是一樣的÷僬蓿可在Application中配置夫植,添加狀態(tài)頁,設(shè)置默認(rèn)狀態(tài)頁
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è)特殊頁面加點(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ù)涧窒,并且該控件并沒有占滿整個(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);
// 重新加載邏輯
}});
使用還是非常簡單的纠吴,這里需要注意,我們所有的CallBack都是自定義的慧瘤,所有的狀態(tà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;
}}
無數(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ì)使用懶加載方式來解決這一問題桦沉。這里我就直接貼代碼了,注釋得非常清楚金闽,無非就是判斷當(dāng)然Fragment是否可見永部,可見的話并且是第一次才加載數(shù)據(jù)。
public abstract class BaseFragment extends Fragment{
public Context mContext;
protected View mRootView;
protected LoadService mBaseLoadService;
/**
* 是否為可見狀態(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);
//如果可見
if (getUserVisibleHint()){
isVisible = true;
onVisible();
}else {
isVisible = false;
onInvisible();
}
}
/**
*可見做懶加載
*/
private void onVisible(){
lazyLoad();
}
private void lazyLoad(){
if (!isVisible || !isPrepared){
return;
}
initData();
isPrepared = false;
}
/**
* 不可見時(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);}
基類還是非常簡單的,我們可以根據(jù)自己的業(yè)務(wù)需求自行拓展懦砂,比如加入Toast等蜒犯。
那么我們Fragment中的代碼就非常簡單了,為了更好的展示效果荞膘,我們?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,再說就跑題了M郎3备摹!至于TabLayoyut和ViewPager結(jié)合Fragment的使用我這里就不介紹了腹暖。
這里把文章中設(shè)計(jì)到的一些資源文件放出來給大家汇在。