打造一個(gè)高效易用的懶加載BaseFragment

首先感謝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)給大家。

timeout.png
custom.png
empty.png
img.jpg
music.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,150評(píng)論 25 708
  • LoadSir是一個(gè)高效易用,低碳環(huán)保,擴(kuò)展性良好的加載反饋?lái)?yè)管理框架,在加載網(wǎng)絡(luò)或其他數(shù)據(jù)時(shí)候,根據(jù)需求切換狀態(tài)...
    KingJA閱讀 16,047評(píng)論 69 125
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,616評(píng)論 19 139
  • 作者介紹馮宇飛 ,現(xiàn)任人人車Android客戶端架構(gòu)師。 本文回顧總結(jié)了人人車公司Android客戶端的架構(gòu)演進(jìn)歷...
    passiontim閱讀 1,652評(píng)論 0 9
  • 終于考完了計(jì)算機(jī),算是了卻了一件大事。姑娘松口氣,然后繼續(xù)努力。為了成為更優(yōu)秀的自己。
    9a63a67e192b閱讀 63評(píng)論 0 1

友情鏈接更多精彩內(nèi)容