-
Notifications
You must be signed in to change notification settings - Fork 1.2k
6. 常见问题(必看)
虽然弹窗已经解决了很多Bug,已经很稳定,但是仍然可能出现Bug。如果出问题,请第一时间看看我的Demo有没有问题,如果Demo没有问题,那往往是你使用不当造成的。
//DataBinding 在 onCreate 调用
binding = DataBindingUtil.bind(getPopupImplView());
//ViewBinding
binding = XXXBinding.bind(getPopupImplView());
弹窗之所以能响应返回键,是因为弹窗默认会获取焦点。如果你调用了isRequestFocus(false)
方法的话,弹窗会失去焦点,从而无法响应返回按键。
如果你并没有调用这个方法,弹窗也无法响应返回键,那往往是弹窗布局内的某个View强制获取焦点了,比如WebView。此时给弹窗的根布局设置2个属性即可,不让View强制获取焦点。
属性如下:
android:focusable="false"
android:focusableInTouchMode="false"
由于弹窗的宿主不是Fragment,而是Activity;所以XPopup目前能做到宿主Activity关闭的时候清除资源避免内存泄漏。但在Fragment中使用,当你的Fragment被destroy了后,如果你设置了XPopup的回调或者使用的是Attach系列弹窗,可能会有内存泄漏。泄漏是由弹窗的popupInfo字段引起的,这个字段可能会引用View对象和XPopupCallback对象。
那为什么我不在弹窗dismiss的时候进行清除资源呢?因为XPopup不确定弹窗消失后还会不会复用,因为你可能会复用弹窗对象;所以popupInfo无法做到在弹窗dismiss的时候进行清除。对于这种Fragment场景的泄漏,你有几种解决方案:
-
也可以无需处理,因为Activity只要关闭,弹窗就全部释放资源
-
XPopup提供了
isDestroyOnDismiss
设置,如果你的弹窗只使用一次,最好设置这个,它能保证在弹窗消失的时候进行彻底的资源释放 -
最坏的情况是,你的弹窗在Fragment中使用,并且弹窗对象会重复使用多次,每个弹窗对象都提供了
destroy()
方法用于彻底释放资源,你可以选择在合适的时间手动调用该方法,即可避免内存泄漏
两种方法:
- 编写弹窗布局的时候高度指定固定的值,比如200dp;
- 可以重写getPopupHeight()方法,返回一个固定值,这种方式更灵活,可以在代码中动态计算;
一般出现在长按场景,比如长按列表Item弹出弹窗,此时不松手继续上下滑动,下层的列表仍然能够滑动。此时需要在长按事件中调用一下XPopup.fixLongClick(v)
:
view.findViewById(R.id.btnShowAttachPoint).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
XPopup.fixLongClick(v);//重要:能保证弹窗弹出后,下层的View无法滑动
builder.asAttachList(new String[]{"置顶", "复制"}, null,new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
toast("click " + text);
}
})
.show();
return true;
}
});
XPopup默认是Dialog实现,由于Android的限制,Dialog中无法直接使用Fragment,所以需要设置isViewMode(true)
;开启View模式后弹出本质上是挂载到decorView上的一个View了,不再是Dialog。
使用Fragment时,有个注意事项如下:
**弹窗开启View模式后,本质就是Activity里一个View。在弹窗内嵌入Fragment的场景中,等同于在View中使用Fragment。
当弹窗消失后,由于Fragment被Activity的FragmentManager缓存,会导致弹窗重新创建/显示的时候,Fragment会命中缓存,生命周期不再执行。为了处理这种情况,只需重写: getInternalFragmentNames() 方法,返回嵌入的Fragment名称,XPopup会在弹窗消失时自动移除Fragment缓存。**
/**
* 在弹窗内嵌入Fragment的场景中,当弹窗后,由于Fragment被Activity的FragmentManager缓存,
* 会导致弹窗重新创建的时候,Fragment会命中缓存,生命周期不再执行。为了处理这种情况,只需重写:
* getInternalFragmentNames() 方法,返回嵌入的Fragment名称,XPopup会自动移除Fragment缓存。
* 名字是: Fragment.getClass().getSimpleName()
* @return
*/
protected List<String> getInternalFragmentNames(){
return null;
}
如果你的弹窗是一次性使用,而非复用,一定要设置.isDestroyOnDismiss(true)
。
当然如果你想自己处理Fragment的移除逻辑,就不用管这个方法了;可以在onDiamiss方法中取移除你的Fragment。
QQ Email: [email protected]
QQ: 16167479