下面列出了android.view.WindowManager#BadTokenException ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
protected void onPostExecute(AndroidAppDeliveryData deliveryData) {
super.onPostExecute(deliveryData);
if (getException() instanceof NotPurchasedException
&& ContextUtil.isAlive(context)
&& (triggeredBy.equals(State.TriggeredBy.DOWNLOAD_BUTTON)
|| triggeredBy.equals(State.TriggeredBy.MANUAL_DOWNLOAD_BUTTON)
)
) {
try {
new PurchaseDialogBuilder((Activity) context, app.getPackageName()).show();
} catch (WindowManager.BadTokenException e1) {
Log.e(getClass().getSimpleName(), "Could not create purchase error dialog: " + e1.getMessage());
}
}
}
private boolean addContainerToWindowManager(int type) {
boolean success = false;
try {
currentContainer = new FrameLayout(container.getContext());
currentContainer.addView(container, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT));
windowManager.addView(currentContainer, createLayoutParams(type));
success = true;
} catch (WindowManager.BadTokenException e) {
removeCurrentContainer();
String errorMessage = e.getMessage();
if (errorMessage == null || !(errorMessage.contains("permission denied") ||
errorMessage.contains("has already been added"))) {
throw e;
}
} finally {
if (!success) {
removeCurrentContainer();
}
}
return success;
}
public static void showErrorAndFinish (final Activity activity, Exception ex) {
try {
Log.e(activity.getClass().getName(), Utils.getErrorMessage(ex));
ex.printStackTrace();
new AlertDialog.Builder(activity)
.setMessage(Utils.getErrorMessage(ex))
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
activity.finish();
}
})
.show();
} catch (WindowManager.BadTokenException unused) {
/* Ignore... happens if the activity was destroyed */
}
}
@Override
public void onCreate(Context context) {
this.cx = context;
wm = (WindowManager) cx.getSystemService(Context.WINDOW_SERVICE);
mHandler = new Handler();
unvisiableView = new View(cx);
int targetColor;
if (Build.VERSION.SDK_INT >= 23) {
targetColor = context.getColor(R.color.colorAccent);
} else {
targetColor = context.getResources().getColor(R.color.colorAccent);
}
unvisiableView.setBackgroundColor(targetColor);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
//创建非模态、不可碰触
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
//放在左上角
params.gravity = Gravity.START | Gravity.TOP;
params.height = 1;
params.width = 1;
//设置弹出View类型
params.type = WINDOW_LEVEL;
try {
wm.addView(unvisiableView, params);
} catch (WindowManager.BadTokenException e) {
LogUtil.e(TAG, e, "无法使用Window type = %d, 降级", WINDOW_LEVEL);
WINDOW_LEVEL = TYPE_TOAST;
params.type = WINDOW_LEVEL;
wm.addView(unvisiableView, params);
}
}
/**
* 显示
*/
public X show() {
if (mRootView == null || mWindowParams == null) {
throw new IllegalArgumentException("WindowParams and view cannot be empty");
}
// 如果当前已经显示取消上一次显示
if (mShow) {
cancel();
}
try {
// 如果这个 View 对象被重复添加到 WindowManager 则会抛出异常
// java.lang.IllegalStateException: View android.widget.TextView{3d2cee7 V.ED..... ......ID 0,0-312,153} has already been added to the window manager.
mWindowManager.addView(mRootView, mWindowParams);
// 当前已经显示
mShow = true;
// 如果当前限定了显示时长
if (mDuration != 0) {
postDelayed(new ToastDismissRunnable(this), mDuration);
}
// 如果设置了拖拽规则
if (mDraggable != null) {
mDraggable.start(this);
}
// 注册 Activity 生命周期
if (mLifecycle != null) {
mLifecycle.register();
}
// 回调监听
if (mListener != null) {
mListener.onShow(this);
}
} catch (NullPointerException | IllegalStateException | WindowManager.BadTokenException e) {
e.printStackTrace();
}
return (X) this;
}
@Override
public AlertDialog show() {
try {
AlertDialog dialog = create();
dialog.setOnDismissListener(mOnDismissListener);
dialog.show();
return dialog;
} catch (WindowManager.BadTokenException ignored) {
return create();
}
}
@Override
public void handleMessage(Message msg) {
// 捕获这个异常,避免程序崩溃
try {
// 目前发现在 Android 7.1 主线程被阻塞之后弹吐司会导致崩溃,可使用 Thread.sleep(5000) 进行复现
// 查看源码得知 Google 已经在 Android 8.0 已经修复了此问题
// 主线程阻塞之后 Toast 也会被阻塞,Toast 因为超时导致 Window Token 失效
mHandler.handleMessage(msg);
} catch (WindowManager.BadTokenException | IllegalStateException ignored) {
// android.view.WindowManager$BadTokenException:Unable to add window -- token android.os.BinderProxy is not valid; is your activity running?
// java.lang.IllegalStateException:java.lang.IllegalStateException:View android.widget.LinearLayout has already been added to the window manager.
}
}
public final void show() {
if (isShown) {
return;
}
isShown = true;
try {
mWindowManager.addView(view, params);
onShow();
} catch (WindowManager.BadTokenException e) {
e.printStackTrace();
}
}
@Override
public AlertDialog show() {
try {
AlertDialog dialog = create();
dialog.setOnDismissListener(mOnDismissListener);
dialog.show();
return dialog;
} catch (WindowManager.BadTokenException ignored) {
return create();
}
}
@Override
public AlertDialog show() {
try {
AlertDialog dialog = create();
dialog.setOnDismissListener(mOnDismissListener);
dialog.show();
return dialog;
} catch (WindowManager.BadTokenException ignored) {
return create();
}
}
private ProgressDialog createProgressDialog(Context mContext) {
ProgressDialog dialog = new ProgressDialog(mContext);
try {
dialog.show();
} catch (WindowManager.BadTokenException e) {}
dialog.setCancelable(false);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setContentView(R.layout.progress_dialog);
return dialog;
}
@Override
@UiThread
public void show() {
try {
super.show();
} catch (WindowManager.BadTokenException e) {
throw new DialogException("Bad window token, you cannot show a dialog before an Activity is created or after it's hidden.");
}
}
@Override
public void show() {
try {
mListBoxPopup.show();
} catch (WindowManager.BadTokenException e) {
notifySelection(null);
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
mDrawer.openDrawer(GravityCompat.START);
return true;
}
if (id == R.id.action_add_friend) {
SimpleAddFriendDialogDesign dial = new SimpleAddFriendDialogDesign(getActivity(), null);
dial.show();
return true;
}
if (id == R.id.action_search) {
HomeSearch searchLayout = (HomeSearch) getActivity().getLayoutInflater().inflate(
R.layout.home_search, null, false);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
PixelFormat.TRANSLUCENT
);
try {
MainActivityHolder activity = (MainActivityHolder) getActivity();
activity.getWindowManager().addView(searchLayout, params);
activity.setSearch(searchLayout);
} catch (WindowManager.BadTokenException e) {
Log.e("MOMO", "exception: " + e);
}
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public AlertDialog show() {
try {
AlertDialog dialog = create();
dialog.setOnDismissListener(mOnDismissListener);
dialog.show();
return dialog;
} catch (WindowManager.BadTokenException ignored) {
return create();
}
}
private static ProgressDialog createAndShowWaitSpinner(Context mContext)
{
ProgressDialog dialog = new ProgressDialog(mContext);
try {
dialog.show();
}
catch (WindowManager.BadTokenException e) {
}
dialog.setCancelable(false);
dialog.setIndeterminate(true);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setContentView(R.layout.wait_spinner);
return dialog;
}
public void handleShow(IBinder windowToken) {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
// If a cancel/hide is pending - no need to show - at this point
// the window token is already invalid and no need to do any work.
if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) {
return;
}
if (mView != mNextView) {
// remove the old view if necessary
handleHide();
mView = mNextView;
Context context = mView.getContext().getApplicationContext();
String packageName = mView.getContext().getOpPackageName();
if (context == null) {
context = mView.getContext();
}
mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
final Configuration config = mView.getContext().getResources().getConfiguration();
final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.x = mX;
mParams.y = mY;
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
mParams.packageName = packageName;
mParams.hideTimeoutMilliseconds = mDuration ==
Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
mParams.token = windowToken;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
// Since the notification manager service cancels the token right
// after it notifies us to cancel the toast there is an inherent
// race and we may attempt to add a window after the token has been
// invalidated. Let us hedge against that.
try {
mWM.addView(mView, mParams);
trySendAccessibilityEvent();
} catch (WindowManager.BadTokenException e) {
/* ignore */
}
}
}
/***
* 显示吐司弹窗
*/
void show() {
if (!isShow()) {
/*
这里解释一下,为什么不复用 WindowManager.LayoutParams 这个对象
因为如果复用了,不同 Activity 之间不能共用一个,第一个 Activity 调用显示方法可以显示出来,但是会导致后面的 Activity 都显示不出来
又或者说,非第一次调用显示方法的 Activity 都会把这个显示请求推送给之前第一个调用显示的 Activity 上面,如果第一个 Activity 已经销毁,还会报以下异常
android.view.WindowManager$BadTokenException:
Unable to add window -- token [email protected] is not valid; is your activity running?
*/
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
/*
// 为什么不能加 TYPE_TOAST,因为通知权限在关闭后设置显示的类型为 Toast 会报错
// android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
params.type = WindowManager.LayoutParams.TYPE_TOAST;
*/
/*
// 这个是旧版本的写法,新版本已经废弃,因为 Activity onPause 方法被调用后这里把 Toast 取消显示了,这样做的原因:防止内存泄露
// 判断是否为 Android 6.0 及以上系统并且有悬浮窗权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(mToast.getView().getContext())) {
// 解决使用 WindowManager 创建的 Toast 只能显示在当前 Activity 的问题
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
}
}
*/
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = android.R.style.Animation_Toast;
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
params.packageName = mPackageName;
// 重新初始化位置
params.gravity = mToast.getGravity();
params.x = mToast.getXOffset();
params.y = mToast.getYOffset();
try {
Activity topActivity = mWindowHelper.getTopActivity();
if (topActivity != null && !topActivity.isFinishing()) {
WindowManager windowManager = (WindowManager) topActivity.getSystemService(Context.WINDOW_SERVICE);
if (windowManager != null) {
windowManager.addView(mToast.getView(), params);
}
}
// 添加一个移除吐司的任务
sendEmptyMessageDelayed(hashCode(), mToast.getDuration() == Toast.LENGTH_LONG ?
IToastStrategy.LONG_DURATION_TIMEOUT : IToastStrategy.SHORT_DURATION_TIMEOUT);
// 当前已经显示
setShow(true);
} catch (IllegalStateException | WindowManager.BadTokenException ignored) {
// 如果这个 View 对象被重复添加到 WindowManager 则会抛出异常
// java.lang.IllegalStateException: View android.widget.TextView has already been added to the window manager.
// 如果 WindowManager 绑定的 Activity 已经销毁,则会抛出异常
// android.view.WindowManager$BadTokenException: Unable to add window -- token [email protected] is not valid; is your activity running?
}
}
}
private void showPastePopup() {
try {
mPastePopupMenu.show(getSelectionRectRelativeToContainingView());
} catch (WindowManager.BadTokenException e) {
}
}