我們來實現Android端的彈框顯示邏輯,由於需要顯示的分享彈框業務種類有八種,所以必要的封裝和抽象是必要的
1.封裝前後臺切換監聽
在應用的主頁的onCreate()中調用:
//根據前後臺切換監聽檢測是否有分享彈窗
AppBackgroundManager.getInstance().initWatcher().setAppStateListener(new AppBackgroundManager.IAppStateChangeListener() {
@Override
public void onAppStateChanged(boolean isAppForceground) {
if (isAppForceground) {
ShareCommandMgr.getInstance().startCheckShareCommand();
}
}
});
考慮到項目中主頁之前還有啓動頁,在前後臺切換管理類的基礎上,我加了一個方法,以便在第一次打開應用時,主頁第一次走onCreate()時也能回調onAppStateChanged
/**
* 開始監聽時調用,只允許調用一次
*/
private boolean isInited = false;
public AppBackgroundManager initWatcher() {
if (!isInited) {
isAppForeground = false;
isInited = true;
}
return this;
}
(因爲註冊的前後臺監聽是在主頁,閃屏頁啓動之後,如果沒有這個方法,第一次啓動APP進入閃屏頁,mListener == null,後續都在前臺,主頁就不會再走回調,而我希望第一次進入主頁也會有回調。請細品代碼哦)
//App前後臺切換
private void onAppForegroundStateChange(boolean isAppForeground) {
if (mListener == null) {
return;
}
mListener.onAppStateChanged(isAppForeground);
}
別忘了在應用的Application的onCreate中增加方法:
/**
* 註冊監聽應用全局activity生命週期的監聽,判斷應用前臺後臺切換
*/
private void registerActivityLifeCycle() {
getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
AppBackgroundManager.getInstance().onActivityStarted(activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
AppBackgroundManager.getInstance().onActivityStopped();
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
2.獲取口令,獲取分享數據
剛剛在前後臺回調中做了如下調用,看看內部是如何封裝的
ShareCommandMgr.getInstance().startCheckShareCommand();
/**
* 分享彈窗管理類
*/
public class ShareCommandMgr {
public static ShareCommandMgr uHelper;
public static ShareCommandMgr getInstance() {
if (uHelper == null) {
synchronized (ShareCommandMgr.class) {
if (uHelper == null) {
uHelper = new ShareCommandMgr();
}
}
}
return uHelper;
}
/**
* 粘貼板是否含自己的口令
* <p>
* #LZ100_200000#
* #LZabcdefg890123456#
* 客戶端判斷 #LZ開頭 和#結尾中間的內容code,
* 若code的長度>16 或等於0則不處理;
*
* @return
*/
public boolean isLzShareCommand() {
if (StringUtils.isEmpty(ClipboardUtils.getText())) {
return false;
}
String command = ClipboardUtils.getText().toString();
if (StringUtils.isTrimEmpty(command)) {
return false;
}
if (command.length() <= 4) {
return false;
}
if (command.startsWith("#LZ") && command.endsWith("#")) {
return true;
}
return false;
}
/**
* 開始解析並顯示口令
*/
public void startCheckShareCommand() {
//如果不是自己的口令直接退出
if (!isLzShareCommand()) {
return;
}
//獲取粘貼板文本口令
String commandFull = ClipboardUtils.getText().toString();
//根據口令調接口
getShareDataByCommand(commandFull);
}
public void getShareDataByCommand(String shareCode) {
RetrofitFactory.composeAndAutoDispose(RetrofitFactory.getAPI().share_detail(shareCode), (AppCompatActivity) ActivityUtils.getTopActivity())
.subscribe(new SmartObserver<ShareCommandData>(ActivityUtils.getTopActivity()) {
@Override
public void onSuccess(BaseBean<ShareCommandData> bean) {
if (bean.getData() == null) {
return;
}
//根據類型顯示不同的口令彈窗
if (bean.getData().equipment != null) {
//顯示設備彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_MACHINE)
.setData(bean.getData(), bean.getData().equipment)
.show();
} else if (bean.getData().equipmentdemand != null) {
//顯示求租彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_RENT_OUT)
.setData(bean.getData(), bean.getData().equipmentdemand)
.show();
} else if (bean.getData().goods != null) {
//顯示商品彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_PRODUCT)
.setData(bean.getData(), bean.getData().goods)
.show();
} else if (bean.getData().demand != null) {
//顯示採購單彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_PURCHASE)
.setData(bean.getData(), bean.getData().demand)
.show();
} else if (bean.getData().recruit != null) {
//顯示招聘彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_RECRUIT)
.setData(bean.getData(), bean.getData().recruit)
.show();
} else if (bean.getData().resume != null) {
//顯示人才簡歷彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_TALENT)
.setData(bean.getData(), bean.getData().resume)
.show();
} else if (bean.getData().userinfo != null) {
//顯示個人主頁彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_PERSONAL)
.setData(bean.getData(), bean.getData().userinfo)
.show();
}else{
Log.i("LZ", "不支持的彈窗類型");
}
//清除粘貼板口令信息,防止重複進入應用重複顯示彈窗
ClipboardUtils.copyText("");
}
@Override
public void onFailure(int code, String errorMsg) {
super.onFailure(code, errorMsg);
}
});
}
3.抽象彈窗顯示
ShareCommandMgr 中顯示彈窗的代碼如下:
//顯示設備彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_MACHINE)
.setData(bean.getData(), bean.getData().equipment)
.show();
我們來看看內部實現,這裏用了工廠模式,以較爲優雅的方式創建不同風格的彈框,畢竟彈框種類不少:
/**
* 分享彈窗工廠
*/
public class ShareCommandFactory {
public static final int TYPE_MACHINE = 0;//機械設備
public static final int TYPE_PURCHASE = 1;//採購單
public static final int TYPE_RENT_OUT = 2;//求租
public static final int TYPE_RECRUIT = 3;//招聘
public static final int TYPE_TALENT = 4;//人才
public static final int TYPE_PERSONAL = 5;//主頁
public static final int TYPE_PRODUCT = 6;//商品
public static ShareCommandFactory uHelper;
public static ShareCommandFactory getInstance() {
if (uHelper == null) {
synchronized (ShareCommandFactory.class) {
if (uHelper == null) {
uHelper = new ShareCommandFactory();
}
}
}
return uHelper;
}
private IShareCommand iShareCommand = null;
/**
* 創建分享彈窗場景實例
*
* @param type
* @return
*/
public ShareCommandFactory newShareCommandViewScene(int type) {
switch (type) {
case TYPE_MACHINE:
iShareCommand = new MachineSence();
break;
case TYPE_PURCHASE:
iShareCommand = new PurchaseSence();
break;
case TYPE_RENT_OUT:
iShareCommand = new RentOutSence();
break;
case TYPE_RECRUIT:
iShareCommand = new RecruitSence();
break;
case TYPE_TALENT:
iShareCommand = new TalentSence();
break;
case TYPE_PERSONAL:
iShareCommand = new PersonalSence();
break;
case TYPE_PRODUCT:
iShareCommand = new ProductSence();
break;
default:
iShareCommand = new MachineSence();
break;
}
return this;
}
/**
* 設置彈窗中的數據
* @param bean
* @param data
* @param <T>
*/
public <T> ShareCommandFactory setData(ShareCommandData bean, T data){
if (iShareCommand != null) {
iShareCommand.setData(bean,data);
}
return this;
}
/**
* 顯示彈窗
*
*/
public void show() {
if (iShareCommand != null) {
iShareCommand.showShareSceneView();
}
}
}
對於彈窗的顯示,我做了小小的抽象,寫了個基類:
/**
* 分享彈窗抽象類
* @param <T>
*/
public abstract class IShareCommand<T> {
/**
* 數據
*/
protected T mData;
protected ShareCommandData mDataParent;
/**
* view
*/
protected View mView;
/**
* 彈窗資源layout
* @return
*/
public abstract int getLayoutResId();
/**
* 綁定數據到界面
*/
public abstract void bindDataToView();
/**
* 界面上點擊查看詳情按鈕
*/
public abstract void navigationTo();
/**
* 設置數據
* @param mDataParent
* @param data
* @return
*/
public IShareCommand setData(ShareCommandData mDataParent,T data) {
this.mDataParent = mDataParent;
mData = data;
return this;
}
/**
* 顯示彈窗
* @return
*/
public IShareCommand showShareSceneView(){
CustomDialog.show(ActivityUtils.getTopActivity(), getLayoutResId(), new CustomDialog.BindView() {
@Override
public void onBind(final CustomDialog dialog, View v) {
mView = v;
//彈窗界面相似邏輯基類統一處理start
v.findViewById(R.id.ll_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.doDismiss();
}
});
v.findViewById(R.id.tv_navigation).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳轉
navigationTo();
dialog.doDismiss();
}
});
GlideImageView avatar = mView.findViewById(R.id.iv_avatar);
TextView username = mView.findViewById(R.id.tv_user_name);
LinearLayout ll_share_user_top = mView.findViewById(R.id.ll_share_user_top);
if (mDataParent.frominfo == null) {
ll_share_user_top.setVisibility(View.GONE);
} else {
avatar.setImageUrl(mDataParent.frominfo.fromavatar);
username.setText(mDataParent.frominfo.nickname);
}
//彈窗界面相似邏輯基類統一處理end
//綁定數據到界面
bindDataToView();
}
});
return this;
}
}
然後每個業務場景的彈窗只需要繼承這個抽象類,實現不同的彈窗風格,設置不同類型的數據,跳轉到自己的詳情頁即可:
比如,其中一個彈窗示例:
/**
* 機械設備分享彈窗
*/
public class MachineSence extends IShareCommand<ShareCommandData.Equipment> {
/**
* 彈窗界面
* @return
*/
@Override
public int getLayoutResId() {
return R.layout.share_command_machine_dialog;
}
/**
* 綁定數據到界面
*/
@Override
public void bindDataToView() {
GlideImageView ivTop = mView.findViewById(R.id.iv_top);
if (!BosUtil.isRealUrl(mData.pic)) {
ivTop.setImageUrl(BosUtil.getRealUrlByShort(mData.pic));
} else {
ivTop.setImageUrl(mData.pic);
}
TextView title = mView.findViewById(R.id.tv_title);
title.setText(mData.title);
TextView tv_name_price = mView.findViewById(R.id.tv_name_price);
if (StringUtils.isEmpty(mData.rentpricelist) || mData.rentpricelist.equals("面議")) {
tv_name_price.setText("面議");
} else {
tv_name_price.setText(mData.rentpricelist);
}
}
/**
* 跳轉
*/
@Override
public void navigationTo() {
ARouter.getInstance().build(RoutingTable.DeviceDetail)
.withString("id", mData.id)
.navigation();
}
}
最後重新看下分享彈窗管理類調用代碼顯示彈窗邏輯:
//顯示設備彈窗
ShareCommandFactory.getInstance()
.newShareCommandViewScene(ShareCommandFactory.TYPE_MACHINE)
.setData(bean.getData(), bean.getData().equipment)
.show();
是不是很優雅的實現了彈窗的顯示,這就是Java封裝與抽象的魅力,這也和平時封裝BaseActivity或者BaseFragment相似,只是這裏多了個工廠模式,很簡單,請客觀細品。