日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等...

發(fā)布時間:2025/4/5 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

LoadSir是一個高效易用,低碳環(huán)保,擴(kuò)展性良好的加載反饋頁管理框架,在加載網(wǎng)絡(luò)或其他數(shù)據(jù)時候,根據(jù)需求切換狀態(tài)頁面,可添加自定義狀態(tài)頁面,如加載中,加載失敗,無數(shù)據(jù),網(wǎng)絡(luò)超時,占位圖,登錄失效等常用頁面。可配合網(wǎng)絡(luò)加載框架,結(jié)合返回狀態(tài)碼,錯誤碼,數(shù)據(jù)進(jìn)行狀態(tài)頁自動切換,封裝使用效果更佳。

效果預(yù)覽

in Activityin Viewin Fragment
PlaceholderMuitl-FragmentViewPage+Fragment

使用場景

下面為大家常見的加載反饋頁面:

loadingerrortimeout
emptycustomplaceholder

面對這么多狀態(tài)頁面,你是不是還在用include的方式,setVisibility(View.VISIBLE/GONE),這種方式即不方便控制,也造成了視圖層級冗余(你要把所有狀態(tài)布局include進(jìn)一個視圖)。如果有一種工具,能把這些事都做了就好了。恰好, ?LoadSir 把這些事做了,接下來我們就來了解一下它。

LoadSir的功能及特點(diǎn)

  • 支持Activity,Fragment,Fragment(v4),View狀態(tài)回調(diào)

  • 適配多個Fragment切換,及Fragment+ViewPager切換,不會狀態(tài)疊加或者狀態(tài)錯亂

  • 利用泛型轉(zhuǎn)換輸入信號和輸出狀態(tài),可根據(jù)網(wǎng)絡(luò)返回體的狀態(tài)碼或者數(shù)據(jù)返回自動適配狀態(tài)頁,實(shí)現(xiàn)全局自動狀態(tài)切換

  • 只加載唯一一個狀態(tài)視圖,不會預(yù)加載全部視圖

  • 可保留標(biāo)題欄(Toolbar,titile view等)

  • 可設(shè)置重新加載點(diǎn)擊事件(OnReloadListener)

  • 可自定義狀態(tài)頁(繼承Callback類)

  • 可在子線程直接切換狀態(tài)

  • 可設(shè)置初始狀態(tài)頁(常用進(jìn)度頁作為初始狀態(tài))

  • 不需要設(shè)置枚舉或者常量狀態(tài)值,直接用狀態(tài)頁類類型(xxx.class)作為狀態(tài)碼

  • 可擴(kuò)展?fàn)顟B(tài)頁面,在配置中添加自定義狀態(tài)頁

  • 可對單個狀態(tài)頁單獨(dú)設(shè)置點(diǎn)擊事件,根據(jù)返回boolean值覆蓋或者結(jié)合OnReloadListener使用,如網(wǎng)絡(luò)錯誤可跳轉(zhuǎn)設(shè)置頁

  • 可全局單例配置,也可以單獨(dú)配置

  • 無預(yù)設(shè)頁面,低耦合,開發(fā)者隨心配置

開始使用LoadSir

LoadSir的使用只需要簡單的三步,三步上籃的三步。

添加依賴

compile?'com.kingja.loadsir:loadsir:1.3.6'

第一步: 配置

全局配置方式

全局配置方式,使用的是單例模式,即獲取的配置都是一樣的。可在Application中配置,添加狀態(tài)頁,設(shè)置初始化狀態(tài)頁,建議使用這種配置方式。

public?class?App?extends?Application?{
????@Override
????public?void?onCreate()?{
????????super.onCreate();
????????LoadSir.beginBuilder()
????.addCallback(new?ErrorCallback())//'添加各種狀態(tài)頁
????.addCallback(new?EmptyCallback())
????.addCallback(new?LoadingCallback())
????.addCallback(new?TimeoutCallback())
????.addCallback(new?CustomCallback())
????.setDefaultCallback(LoadingCallback.class)//設(shè)置默認(rèn)狀態(tài)頁
????.commit();
????}
}

單獨(dú)配置方式

如果你即想保留全局配置,又想在某個特殊頁面加點(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)?{
????//?重新加載邏輯
}
????????});

第二步: 注冊

在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)?{
//?重新加載邏輯
????????}
????});
}}

在View 中使用

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);
????????//?重新加載邏輯
????}
});

在Fragment 中使用

由于Fragment添加到Activitiy方式多樣,比較特別,所以在Fragment中注冊方式不同于上面兩種,大家先看模板代碼:

@Nullable
@Override
public?View?onCreateView(LayoutInflater?inflater,?@Nullable?ViewGroup?container,?@Nullable?Bundle
????????savedInstanceState)?{
????//第一步:獲取布局View
????rootView?=?View.inflate(getActivity(),?R.layout.fragment_a_content,?null);
????//第二步:注冊布局View
????LoadService?loadService?=?LoadSir.getDefault().register(rootView,?new?Callback.OnReloadListener()?{
????????@Override
????????public?void?onReload(View?v)?{
//?重新加載邏輯
????????}
????});
????//第三步:返回LoadSir生成的LoadLayout
????return?loadService.getLoadLayout();
}

第三步: 回調(diào)

直接回調(diào)

protected?void?loadNet()?{
????????//?進(jìn)行網(wǎng)絡(luò)訪問...
????????//?進(jìn)行回調(diào)
????????loadService.showSuccess();//成功回調(diào)
????????loadService.showCallback(EmptyCallback.class);//其他回調(diào)
????}

轉(zhuǎn)換器回調(diào) (推薦使用)

如果你不想再每次回調(diào)都要手動進(jìn)行的話,可以選擇注冊的時候加入轉(zhuǎn)換器,可根據(jù)返回的數(shù)據(jù),適配對應(yīng)的回調(diào)。

LoadService?loadService?=?LoadSir.getDefault().register(this,?new?Callback.OnReloadListener()?{
????@Override
????public?void?onReload(View?v)?{
//?重新加載邏輯
????}},?new?Convertor()?{@Overridepublic?Class?extends?Callback>?map(HttpResult?httpResult)?{
????????Class?extends?Callback>?resultCode?=?SuccessCallback.class;switch?(httpResult.getResultCode())?{case?SUCCESS_CODE://成功回調(diào)if?(httpResult.getData().size()?==?0)?{
????????resultCode?=?EmptyCallback.class;
????}else{
????????resultCode?=?SuccessCallback.class;
????}break;case?ERROR_CODE:
????resultCode?=?ErrorCallback.class;break;
????????}return?resultCode;
????}
});

回調(diào)的時候直接傳入轉(zhuǎn)換器指定的數(shù)據(jù)類型。

loadService.showWithConvertor(httpResult);

自定義回調(diào)頁

LoadSir為了完全解耦,沒有預(yù)設(shè)任何狀態(tài)頁,開發(fā)者根據(jù)需求自定義自己的回調(diào)頁面,比如加載中,沒數(shù)據(jù),錯誤,超時等常用頁面,
設(shè)置布局及自定義點(diǎn)擊邏輯

public?class?CustomCallback?extends?Callback?{
????@Override
????protected?int?onCreateView()?{
????????return?R.layout.layout_custom;
????}

????@Override
????protected?boolean?onRetry(final?Context?context,?View?view)?{
????????//布局點(diǎn)擊事件
????????Toast.makeText(context.getApplicationContext(),?"Hello?mother?fuck!?: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;//返回true則覆蓋了register時傳入的重試點(diǎn)擊事件,返回false則兩個都執(zhí)行
????}

????//是否在顯示Callback視圖的時候顯示原始圖(SuccessView),返回true顯示,false隱藏
????@Override
????public?boolean?getSuccessVisible()?{
????????return?super.getSuccessVisible();
????}

????//將Callback添加到當(dāng)前視圖時的回調(diào),View為當(dāng)前Callback的布局View
????@Override
????public?void?onAttach(Context?context,?View?view)?{
????????super.onAttach(context,?view);
????}

????//將Callback從當(dāng)前視圖刪除時的回調(diào),View為當(dāng)前Callback的布局View
????@Override
????public?void?onDetach()?{
????????super.onDetach(context,?view);
????}
}

動態(tài)修改Callback

loadService?=?LoadSir.getDefault().register(...);
loadService.setCallBack(EmptyCallback.class,?new?Transport()?{
???@Override
???public?void?order(Context?context,?View?view)?{
???????TextView?mTvEmpty?=?(TextView)?view.findViewById(R.id.tv_empty);
???????mTvEmpty.setText("fine,?no?data.?You?must?fill?it!");
???}
});

代碼混淆

-dontwarn?com.kingja.loadsir.**
-keep?class?com.kingja.loadsir.**?{*;}

占位圖布局效果

placeholder效果狀態(tài)頁類似ShimmerRecyclerView的效果. LoadSir只用了一個自定義狀態(tài)頁P(yáng)laceHolderCallback就完成類似的效果,是不是很棒 :p

看到這,想必各位使用LoadSir應(yīng)該沒問題了,如果還想再進(jìn)一步了解它的內(nèi)部結(jié)構(gòu),可以繼續(xù)往下看。

原理解析

流程圖

關(guān)鍵類

  • LoadSir:提供單例模式獲取全局唯一實(shí)例,內(nèi)部保存配置信息,根據(jù)配置創(chuàng)建LoadService。

  • LoadService:具體操作服務(wù)類,提供showSuccess,showCallback,showWithCoverator等方法來進(jìn)行狀態(tài)頁回調(diào)。

  • LoadLayout:最終顯示在用戶面前的視圖View,替換了原布局,是LoadService直接操作對象,要顯示的狀態(tài)頁的視圖會被添加到LoadLayout上。

  • Callback:狀態(tài)頁抽象類,抽象自定義布局和自定義點(diǎn)擊事件兩個方法留給子類實(shí)現(xiàn)。

  • Coverator:轉(zhuǎn)換接口,可將網(wǎng)絡(luò)返回實(shí)體轉(zhuǎn)換成對應(yīng)的狀態(tài)頁,達(dá)到自動適配狀態(tài)頁的目的。

我們直接觀察在Activity中普通加載和使用LoadSir加載視圖的區(qū)別

>>>沒使用LoadSir

>>>使用LoadSir

大家可以看到,LoadSir用LoadLayout把原來的布局給替代掉了,原來的布局加在了LoadLayout上,其它自定義的狀態(tài)頁也同樣會被加到這個LoadLayout上(顯示的時候),而且LoadLayout的子View只有一個,就是當(dāng)前要顯示的狀態(tài)頁布局,并沒有把當(dāng)前不顯示的比如加載中布局,錯誤布局,無數(shù)據(jù)布局加載進(jìn)來,這也是LoadSir的優(yōu)點(diǎn)之一,按需加載,并且只加載一個狀態(tài)布局。

>>>替換邏輯

public?static?TargetContext?getTargetContext(Object?target)?{
????????ViewGroup?contentParent;
????????Context?context;
????????if?(target?instanceof?Activity)?{
Activity?activity?=?(Activity)?target;
context?=?activity;
contentParent?=?(ViewGroup)?activity.findViewById(android.R.id.content);
????????}?else?if?(target?instanceof?View)?{
View?view?=?(View)?target;
contentParent?=?(ViewGroup)?(view.getParent());
context?=?view.getContext();
????????}?else?{
throw?new?IllegalArgumentException("The?target?must?be?within?Activity,?Fragment,?View.");
????????}
???????...
????????if?(contentParent?!=?null)?{
contentParent.removeView(oldContent);
????????}
????????return?new?TargetContext(context,?contentParent,?oldContent,?childIndex);
????}

大家可以看到,在Activity和View中的情況都比較簡單,直接獲取target的父控件,然后在父控件中替換掉該布局即可。在Fragment中,由于可能多個Fragment的布局View并存在一個父控件里,所以不能簡單地使用父控件刪除子View方式替換,也有可能父控件是ViewPager,不能通過addView()的方式添加LoadLayout。因此Fragment的注冊方式是直接返回了LoadLayout到Activity上。這樣也達(dá)到了一樣的目的。

下面是ViewPager+Fragment場景中使用LoadSir的視圖,兩個Fragment用各自的LoadLayout進(jìn)行視圖分離,避免了狀態(tài)頁疊加或錯位。

看到這的童鞋應(yīng)該也大概知道LoadSir是怎么回事了,如果想明白LoadSir的代碼實(shí)現(xiàn),請繼續(xù)往下看。

源碼解析

我們按上面三步上籃的步驟來稍微分析下源碼

>>>第一步:配置

單例模式獲取LoadSir,在LoadSir構(gòu)造的時候創(chuàng)建默認(rèn)配置

public?static?LoadSir?getDefault()?{
????????if?(loadSir?==?null)?{
synchronized?(LoadSir.class)?{
????if?(loadSir?==?null)?{
????????loadSir?=?new?LoadSir();
????}
}
????????}
????????return?loadSir;
????}

????private?LoadSir()?{
????????this.builder?=?new?Builder();
????}

Builder主要提供添加狀態(tài)頁,和設(shè)置默認(rèn)狀態(tài)頁的方法

public?static?class?Builder?{
????????private?List?callbacks?=?new?ArrayList<>();private?Class?extends?Callback>?defaultCallback;public?Builder?addCallback(Callback?callback)?{
callbacks.add(callback);return?this;
????????}public?Builder?setDefaultCallback(Class?extends?Callback>?defaultCallback)?{this.defaultCallback?=?defaultCallback;return?this;
????????}
??????...public?LoadSir?build()?{return?new?LoadSir(this);
????????}
????}

LoadSir提供beginBuilder()…commit()來設(shè)置全局配置。

public?class?LoadSir??{
???...
????public?static?Builder?beginBuilder()?{
????????return?new?Builder();
????}

????public?static?class?Builder?{

????????public?void?commit()?{
getDefault().setBuilder(this);
????????}
??????...
????}
}

>>>第二步:注冊

LoadSir注冊后返回的是LoadService,一看名字大家就明白這是服務(wù)類,就是我們所說的Service層。

public?LoadService?register(Object?target,?Callback.OnReloadListener?onReloadListener)?{
????????return?register(target,?onReloadListener,?null);
????}

????public??LoadService?register(Object?target,?Callback.OnReloadListener?onReloadListener,?Convertor
convertor)?{
????????TargetContext?targetContext?=?LoadSirUtil.getTargetContext(target);return?new?LoadService<>(convertor,?targetContext,?onReloadListener,?builder);
????}

在LoadService的構(gòu)造方法中根據(jù)target等信息創(chuàng)建Success視圖,并且生成LoadLayout,相當(dāng)于LoadSir每次注冊都會創(chuàng)建一個LoadLayout。

LoadService(Convertor?convertor,?TargetContext?targetContext,?Callback
.OnReloadListener?onReloadListener,?LoadSir.Builder?builder)?{this.convertor?=?convertor;
????????Context?context?=?targetContext.getContext();
????????View?oldContent?=?targetContext.getOldContent();
????????loadLayout?=?new?LoadLayout(context,?onReloadListener);
????????loadLayout.addCallback(new?SuccessCallback(oldContent,?context,
????onReloadListener));if?(targetContext.getParentView()?!=?null)?{
targetContext.getParentView().addView(loadLayout,?targetContext.getChildIndex(),?oldContent
????????.getLayoutParams());
????????}
????????initCallback(builder);
????}

>>>第三步:回調(diào)

LoadService的三個回調(diào)方法最終調(diào)用的都是loadLayout.showCallback(callback);

public?void?showSuccess()?{
????????loadLayout.showCallback(SuccessCallback.class);
????}

????public?void?showCallback(Class?extends?Callback>?callback)?{
????????loadLayout.showCallback(callback);
????}

????public?void?showWithConvertor(T?t)?{
????????if?(convertor?==?null)?{
throw?new?IllegalArgumentException("You?haven't?set?the?Convertor.");
????????}
????????loadLayout.showCallback(convertor.map(t));
????}

我們直接看LoadLayout的showCallback方法,先做Callback是否配置判斷,然后進(jìn)行線程安全操作。重點(diǎn)還是showCallbackView(callback);

public?void?showCallback(final?Class?extends?Callback>?callback)?{
????????if?(!callbacks.containsKey(callback))?{
throw?new?IllegalArgumentException(String.format("The?Callback?(%s)?is?nonexistent.",?callback
????????.getSimpleName()));
????????}
????????if?(LoadSirUtil.isMainThread())?{
showCallbackView(callback);
????????}?else?{
postToMainThread(callback);
????????}
????}

這個方法可以說是最后的執(zhí)行者,就做兩件事,刪除LoadLayout所有子View(重置),添加指定的布局頁View(回調(diào))。

private?void?showCallbackView(Class?extends?Callback>?status)?{
????????if?(getChildCount()?>?0)?{
removeAllViews();
????????}
????????for?(Class?key?:?callbacks.keySet())?{
if?(key?==?status)?{
????addView(callbacks.get(key).getRootView());
}
????????}
????}

自此,LoadSir一個完整的配置,注冊,回調(diào)的過程完成了。不知道你們明白了沒,反正我是有點(diǎn)口渴了。

總結(jié)

建議在Application中全局配置,在BaseActivity,BaseFragment或者M(jìn)VP中封裝使用,能極大的減少代碼量,讓你的代碼更加優(yōu)雅,生活更加愉快。時間和個人能力有限,如果大家發(fā)現(xiàn)需要改進(jìn)的地方,歡迎提交issue。
如果這個庫對你有用的話,也請點(diǎn)個star。

Github傳送門:https://github.com/KingJA/LoadSir

大家都在看

Android仿抖音的音樂旋轉(zhuǎn)效果

安卓技術(shù)架構(gòu)演進(jìn)及未來

Android應(yīng)用安全提升攻略

Android性能優(yōu)化指南 文末附花絮視頻

歡迎前往安卓巴士博客區(qū)投稿,技術(shù)成長于分享

期待巴友留言,共同探討學(xué)習(xí)

總結(jié)

以上是生活随笔為你收集整理的activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。