问题
1.网络请求过快,loading show之后立马dismiss 造成屏幕闪烁
2.一个页面多个请求,导致 show dismiss show dismiss 闪烁问题
这是一个很常见的问题,优化完以后,用户体验直接+100分。
思路
参考:ContentLoadingProgressBar所写
- 当展示时间少于一个阈值(500ms)时不展示。
- 每次展示最少展示(500ms)。
只要完成这两效果就不会有闪烁问题。
实现
-
show的时候,发送一个延迟500ms的
mHandler.postDelayed()任务
,在这个任务时间到了执行的过程中,判断是不是已经dismiss了,如果dismiss则不展示。 -
dismiss的时候,移除之前show的延迟任务,并且已经show了的话,如果时间过短,则延迟dismiss。如果时间长的话,直接dismiss
-
处理内存泄漏问题。在
onAttachedToWindow
、onDetachedFromWindow
、onDestroy
的时候,得移除handler中的任务
天坑
简简单单的实现完了,开开心心的用在项目中,结果翻车了。
测试反应几天,总有那么一次两次,dialog show了,并且dismiss关不掉。并且无法复现。
反反复复看代码,啥毛病没有。
终于,最后定位在mHandler.removeCallbacks(mDelayedShow);
有时候会失效。原因未知,网上也是众说纷纭。什么前后台切换,会导致Runnable
重新构建,所以remove的时候对象变了等。
总结:removeMessages的object对象会改变,导致移除失败
源码:
解决:
直接不用object,用what进行判断
问题2:
扫码等页面时,可能会触发onAttachedToWindow
,这时如果刚好发了一个延迟dismiss的handler信息,刚好被remove了。就无法正常关闭
代码
dialog样式换成自己的
/**
*
* loading...
*
* 防止网络请求过快,loading show之后立马dismiss 造成屏幕闪烁
* 防止一个页面多个请求,导致 show dismiss show dismiss 闪烁问题
* 参考谷歌的 ContentLoadingProgressBar 写的
*
* mHandler.removeCallbacks 有时会失效,原因未知
*/
public class ContentLoadingDialog extends AppCompatDialog {
public ContentLoadingDialog(Context context) {
super(context, R.style.Theme_AppCompat_DayNight_Dialog);
initView(context);
}
public ContentLoadingDialog(Context context, int theme) {
super(context, R.style.Theme_AppCompat_DayNight_Dialog);
initView(context);
}
protected ContentLoadingDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
initView(context);
}
private void initView(Context context) {
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
getWindow().setDimAmount(0f);
// dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setCancelable(true);
setCanceledOnTouchOutside(false);
setContentView(R.layout.dialog_loading);
BackgroundLayout backgroundLayout = findViewById(R.id.background);
backgroundLayout.setBaseColor(context.getResources().getColor(R.color.color_b1000000));
backgroundLayout.setCornerRadius(10);
FrameLayout containerFrame = findViewById(R.id.container);
int wrapParam = UIUtils.dip2px(GlobalApplication.getContext(),30);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(wrapParam, wrapParam);
SpinView view = new SpinView(context);
containerFrame.addView(view, params);
view.setAnimationSpeed(1);
TextView label = findViewById(R.id.label);
label.setVisibility(View.VISIBLE);
label.setText("正在加载中...");
}
/**
* show以后在此期间调用dismiss 则不展示
*/
private static final int MIN_SHOW_TIME = 500;
/**
* 最小展示时间,show以后最少展示的时间
*/
private static final int MIN_DELAY = 500;
private long mStartTime = -1;
private boolean mPostedHide = false;
private boolean mPostedShow = false;
private boolean mDismissed = false;
private static final int SHOW_HANDLER_WHAT = 964;
private static final int HIDE_HANDLER_WHAT = 965;
private final Handler mHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_HANDLER_WHAT:
mPostedShow = false;
if (!mDismissed) {
mStartTime = System.currentTimeMillis();
show();
}
break;
case HIDE_HANDLER_WHAT:
mPostedHide = false;
mStartTime = -1;
dismiss();
break;
default:
dismiss();
break;
}
super.handleMessage(msg);
}
};
public void showDialog() {
ThreadUtils.runOnUiThread(() -> {
mStartTime = -1;
mDismissed = false;
mHandler.removeMessages(HIDE_HANDLER_WHAT);
mPostedHide = false;
if (!mPostedShow) {
mHandler.sendEmptyMessageDelayed(SHOW_HANDLER_WHAT, MIN_DELAY);
mPostedShow = true;
}
});
}
public void hideDialog() {
ThreadUtils.runOnUiThread(() -> {
mDismissed = true;
mHandler.removeMessages(SHOW_HANDLER_WHAT);
mPostedShow = false;
long diff = System.currentTimeMillis() - mStartTime;
if (diff >= MIN_SHOW_TIME || mStartTime == -1) {
dismiss();
} else {
if (!mPostedHide) {
mHandler.sendEmptyMessageDelayed(HIDE_HANDLER_WHAT, MIN_SHOW_TIME - diff);
mPostedHide = true;
}
}
});
}
public void close(){
removeCallbacks();
if (isShowing()){
dismiss();
}
}
private void removeCallbacks() {
mHandler.removeMessages(HIDE_HANDLER_WHAT);
mHandler.removeMessages(SHOW_HANDLER_WHAT);
}
}