public class ToastWiget {
private static Toast mToast;
//解决7.x WindowManager$BadTokenException
//避免多次反射
private static boolean isReflectedHandler = false;
public static void makeText(CharSequence text, int duration) {
View v = LayoutInflater.from(Sheng.getInstance()).inflate(R.layout.toast_wiget, null);
TextView textView = (TextView) v.findViewById(R.id.content);
textView.setText(text);
if (mToast == null) {
mToast = new Toast(Sheng.getInstance());
}
mToast.setDuration(duration);
mToast.setView(v);
int sdkInt = Build.VERSION.SDK_INT;
if (sdkInt >= Build.VERSION_CODES.N && sdkInt < Build.VERSION_CODES.O && !isReflectedHandler) {
reflectTNHandler(mToast);
//这里为了避免多次反射,使用一个标识来限制
isReflectedHandler = true;
}
mToast.show();
//测试重现
// try {
// Thread.sleep(4000);
// } catch (InterruptedException mE) {
// mE.printStackTrace();
// }
}
public static void makeText(CharSequence text) {
makeText(text, Toast.LENGTH_SHORT);
}
public void setGravity(int gravity, int xOffset, int yOffset) {
if (mToast != null) {
mToast.setGravity(gravity, xOffset, yOffset);
}
}
//--------
public static class SafelyHandlerWarpper extends Handler {
private Handler impl;
public SafelyHandlerWarpper(Handler impl) {
this.impl = impl;
}
@Override
public void dispatchMessage(Message msg){
try {
super.dispatchMessage(msg);
} catch (Exception ignored) {
}
}
@Override
public void handleMessage(Message msg) {
impl.handleMessage(msg);//需要委托给原Handler执行
}
}
private static void reflectTNHandler(Toast toast) {
try {
Field tNField = toast.getClass().getDeclaredField("mTN");
if (tNField == null) {
return;
}
tNField.setAccessible(true);
Object TN = tNField.get(toast);
if (TN == null) {
return;
}
Field handlerField = TN.getClass().getDeclaredField("mHandler");
if (handlerField == null) {
return;
}
handlerField.setAccessible(true);
handlerField.set(TN, new ProxyTNHandler(TN));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static class ProxyTNHandler extends Handler {
private Object tnObject;
private Method handleShowMethod;
private Method handleHideMethod;
ProxyTNHandler(Object tnObject) {
this.tnObject = tnObject;
try {
this.handleShowMethod = tnObject.getClass().getDeclaredMethod("handleShow", IBinder.class);
this.handleShowMethod.setAccessible(true);
this.handleHideMethod = tnObject.getClass().getDeclaredMethod("handleHide");
this.handleHideMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0: {
//SHOW
IBinder token = (IBinder) msg.obj;
if (handleShowMethod != null) {
try {
handleShowMethod.invoke(tnObject, token);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (WindowManager.BadTokenException e) {
//显示Toast时添加BadTokenException异常捕获
e.printStackTrace();
}
}
break;
}
case 1: {
//HIDE
if (handleHideMethod != null) {
try {
handleHideMethod.invoke(tnObject);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
break;
}
case 2: {
//CANCEL
if (handleHideMethod != null) {
try {
handleHideMethod.invoke(tnObject);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
break;
}
}
super.handleMessage(msg);
}
}
}