Skip to content

Commit 66640a2

Browse files
committed
修复复用 BaseDialog 或 BasePopupWindow 对象会出现崩溃的问题
1 parent 27dca99 commit 66640a2

3 files changed

Lines changed: 83 additions & 17 deletions

File tree

app/src/main/java/com/hjq/demo/ui/activity/DialogActivity.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import androidx.annotation.Nullable;
88
import com.hjq.bar.TitleBar;
99
import com.hjq.base.BaseDialog;
10+
import com.hjq.base.BasePopupWindow;
1011
import com.hjq.demo.R;
1112
import com.hjq.demo.aop.SingleClick;
1213
import com.hjq.demo.app.AppActivity;
@@ -45,6 +46,9 @@ public final class DialogActivity extends AppActivity {
4546
/** 等待对话框 */
4647
private BaseDialog mWaitDialog;
4748

49+
/** 菜单弹窗 */
50+
private BasePopupWindow mListPopup;
51+
4852
@Override
4953
protected int getLayoutId() {
5054
return R.layout.dialog_activity;
@@ -525,12 +529,16 @@ public void onCancel(@NonNull BaseDialog dialog) {
525529

526530
@Override
527531
public void onRightClick(TitleBar titleBar) {
528-
// 菜单弹窗
529-
new ListPopup.Builder(this)
532+
if (mListPopup == null) {
533+
mListPopup = new ListPopup.Builder(this)
530534
.setList("选择拍照", "选取相册")
531535
.addOnShowListener(popupWindow -> toast("PopupWindow 显示了"))
532536
.addOnDismissListener(popupWindow -> toast("PopupWindow 销毁了"))
533537
.setListener((ListPopup.OnListener<String>) (popupWindow, position, s) -> toast("点击了:" + s))
534-
.showAsDropDown(titleBar.getRightView());
538+
.create();
539+
}
540+
if (!mListPopup.isShowing()) {
541+
mListPopup.showAsDropDown(titleBar.getRightView());
542+
}
535543
}
536544
}

library/base/src/main/java/com/hjq/base/BaseDialog.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ public class BaseDialog extends AppCompatDialog implements LifecycleOwner,
5353
ActivityAction, ResourcesAction, HandlerAction, ClickAction, AnimAction, KeyboardAction,
5454
DialogInterface.OnShowListener, DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
5555

56-
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
56+
@NonNull
57+
private LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
5758

5859
@NonNull
5960
private final List<BaseDialog.OnShowListener> mShowListeners = new ArrayList<>();
@@ -78,28 +79,28 @@ public BaseDialog(@NonNull Context context, @StyleRes int themeResId) {
7879
@Override
7980
protected void onCreate(@Nullable Bundle savedInstanceState) {
8081
super.onCreate(savedInstanceState);
81-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
82+
handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
8283
}
8384

8485
@Override
8586
protected void onStart() {
8687
super.onStart();
87-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
88+
handleLifecycleEvent(Lifecycle.Event.ON_START);
8889
}
8990

9091
@Override
9192
protected void onStop() {
9293
super.onStop();
93-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
94-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
94+
handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
95+
handleLifecycleEvent(Lifecycle.Event.ON_STOP);
9596
}
9697

9798
/**
9899
* {@link DialogInterface.OnShowListener}
99100
*/
100101
@Override
101102
public void onShow(DialogInterface dialog) {
102-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
103+
handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
103104
// 这里解释一下为什么要创建一个新的 ArrayList,这是因为执行监听方法可能会删除 List 集合中的元素
104105
// 例如 Builder 类中的 postDelayed 方法,就会移除监听对象,所以这里遍历可能出现 ConcurrentModificationException
105106
List<BaseDialog.OnShowListener> listeners = new ArrayList<>(mShowListeners);
@@ -124,7 +125,7 @@ public void onCancel(DialogInterface dialog) {
124125
*/
125126
@Override
126127
public void onDismiss(DialogInterface dialog) {
127-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
128+
handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
128129
List<BaseDialog.OnDismissListener> listeners = new ArrayList<>(mDismissListeners);
129130
for (OnDismissListener listener : listeners) {
130131
listener.onDismiss(this);
@@ -137,6 +138,34 @@ public Lifecycle getLifecycle() {
137138
return mLifecycle;
138139
}
139140

141+
/**
142+
* 处理 Lifecycle 事件
143+
*/
144+
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
145+
// 以下代码主要是为了解决复用 BaseDialog 对象会出现异常的问题
146+
// https://github.com/androidx/androidx/blob/4bb422f5c09d4ed7200f1bdc03a463b39743af85/lifecycle/lifecycle-runtime/src/commonMain/kotlin/androidx/lifecycle/LifecycleRegistry.kt#L89
147+
switch (mLifecycle.getCurrentState()) {
148+
case INITIALIZED:
149+
if (event == Lifecycle.Event.ON_DESTROY) {
150+
// 如果当前是初始化状态,并且下一个状态事件是销毁,必须要有 Create 事件过渡,否则会出现报错
151+
// java.lang.IllegalStateException: State must be at least 'CREATED' to be moved to `DESTROYED` in component
152+
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
153+
}
154+
break;
155+
case DESTROYED:
156+
if (event != Lifecycle.Event.ON_DESTROY) {
157+
// 如果当前是销毁状态,并且下一个状态事件不是销毁,需要重置一下 Lifecycle,否则会出现报错
158+
// java.lang.IllegalStateException: State is 'DESTROYED' and cannot be moved to `STARTED` in component
159+
mLifecycle = new LifecycleRegistry(this);
160+
}
161+
break;
162+
default:
163+
break;
164+
}
165+
// 处理下一个状态事件
166+
mLifecycle.handleLifecycleEvent(event);
167+
}
168+
140169
/**
141170
* 获取 Dialog 的根布局
142171
*/

library/base/src/main/java/com/hjq/base/BasePopupWindow.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ public class BasePopupWindow extends PopupWindow
5454
implements LifecycleOwner, ActivityAction, HandlerAction, ClickAction,
5555
AnimAction, KeyboardAction, PopupWindow.OnDismissListener {
5656

57-
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
57+
@NonNull
58+
private LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
5859

5960
@NonNull
6061
private final Context mContext;
@@ -155,9 +156,9 @@ public void removeOnDismissListener(@Nullable BasePopupWindow.OnDismissListener
155156
}
156157

157158
public void onShow() {
158-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
159-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
160-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
159+
handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
160+
handleLifecycleEvent(Lifecycle.Event.ON_START);
161+
handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
161162
List<BasePopupWindow.OnShowListener> listeners = new ArrayList<>(mShowListeners);
162163
for (BasePopupWindow.OnShowListener listener : listeners) {
163164
listener.onShow(this);
@@ -169,9 +170,9 @@ public void onShow() {
169170
*/
170171
@Override
171172
public void onDismiss() {
172-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
173-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
174-
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
173+
handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
174+
handleLifecycleEvent(Lifecycle.Event.ON_STOP);
175+
handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
175176
List<BasePopupWindow.OnDismissListener> listeners = new ArrayList<>(mDismissListeners);
176177
for (BasePopupWindow.OnDismissListener listener : listeners) {
177178
listener.onDismiss(this);
@@ -202,6 +203,34 @@ public void dismiss() {
202203
super.dismiss();
203204
}
204205

206+
/**
207+
* 处理 Lifecycle 事件
208+
*/
209+
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
210+
// 以下代码主要是为了解决复用 BasePopupWindow 对象会出现异常的问题
211+
// https://github.com/androidx/androidx/blob/4bb422f5c09d4ed7200f1bdc03a463b39743af85/lifecycle/lifecycle-runtime/src/commonMain/kotlin/androidx/lifecycle/LifecycleRegistry.kt#L89
212+
switch (mLifecycle.getCurrentState()) {
213+
case INITIALIZED:
214+
if (event == Lifecycle.Event.ON_DESTROY) {
215+
// 如果当前是初始化状态,并且下一个状态事件是销毁,必须要有 Create 事件过渡,否则会出现报错
216+
// java.lang.IllegalStateException: State must be at least 'CREATED' to be moved to `DESTROYED` in component
217+
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
218+
}
219+
break;
220+
case DESTROYED:
221+
if (event != Lifecycle.Event.ON_DESTROY) {
222+
// 如果当前是销毁状态,并且下一个状态事件不是销毁,需要重置一下 Lifecycle,否则会出现报错
223+
// java.lang.IllegalStateException: State is 'DESTROYED' and cannot be moved to `STARTED` in component
224+
mLifecycle = new LifecycleRegistry(this);
225+
}
226+
break;
227+
default:
228+
break;
229+
}
230+
// 处理下一个状态事件
231+
mLifecycle.handleLifecycleEvent(event);
232+
}
233+
205234
@Override
206235
public <V extends View> V findViewById(@IdRes int id) {
207236
return getContentView().findViewById(id);

0 commit comments

Comments
 (0)