我们来实现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相似,只是这里多了个工厂模式,很简单,请客观细品。