5 years before we know the new version of Android using Toast of those pits, we have given you a good summary

Huawei, Samsung and other models after disabling the notification permission Toast does not pop up

the reason

After a review of source code found Toast, Toast display to be achieved through INotificationManager class, and when the notice is disabled, such calls will return an exception, it does not show cause notice, the source code is as follows:

public void show() {
  if (mNextView == null) {
    throw new RuntimeException("setView must have been called");
  }

  INotificationManager service = getService();
  String pkg = mContext.getOpPackageName();
  TN tn = mTN;
  tn.mNextView = mNextView;

  try {
    service.enqueueToast(pkg, tn, mDuration);
  } catch (RemoteException e) {
    // 权限禁用后走这里,这里是空方法,所以会发生既不crash又无响应的情况
  }
}

5 years before we know the new version of Android using Toast of those pits, we have given you a good summary

This is a google of bug, part of millet phone rewrite Toast code, so you can execute properly, we can be bypassed by way of reflection, and will have the following solutions :

Solution

public class ToastUtils {
    private static Object iNotificationManagerObj;

    /**
     * @param context
     * @param message
     */
    public static void show(Context context, String message) {
        show(context.getApplicationContext(), message, Toast.LENGTH_SHORT);
    }

    /**
     * @param context
     * @param message
     */
    public static void show(Context context, String message, int duration) {
        if (TextUtils.isEmpty(message)) {
            return;
        }
        //后setText 兼容小米默认会显示app名称的问题
        Toast toast = Toast.makeText(context, null, duration);
        toast.setText(message);
        if (isNotificationEnabled(context)) {
            toast.show();
        } else {
            showSystemToast(toast);
        }
    }

    /**
     * 显示系统Toast
     */
    private static void showSystemToast(Toast toast) {
        try {
            Method getServiceMethod = Toast.class.getDeclaredMethod("getService");
            getServiceMethod.setAccessible(true);
            //hook INotificationManager
            if (iNotificationManagerObj == null) {
                iNotificationManagerObj = getServiceMethod.invoke(null);

                Class iNotificationManagerCls = Class.forName("android.app.INotificationManager");
                Object iNotificationManagerProxy = Proxy.newProxyInstance(toast.getClass().getClassLoader(), new Class[]{iNotificationManagerCls}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //强制使用系统Toast
                        if ("enqueueToast".equals(method.getName())
                                || "enqueueToastEx".equals(method.getName())) {  //华为p20 pro上为enqueueToastEx
                            args[0] = "android";
                        }
                        return method.invoke(iNotificationManagerObj, args);
                    }
                });
                Field sServiceFiled = Toast.class.getDeclaredField("sService");
                sServiceFiled.setAccessible(true);
                sServiceFiled.set(null, iNotificationManagerProxy);
            }
            toast.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 消息通知是否开启
     *
     * @return
     */
    private static boolean isNotificationEnabled(Context context) {
        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
        boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled();
        return areNotificationsEnabled;
    }
}

5 years before we know the new version of Android using Toast of those pits, we have given you a good summary

Toast the same content can not be repeated short-term pop

the reason

When we repeated clicks Toast, Toast will continuously pop up a lot, good visual experience, so the spread of the Internet that these solutions:

Toast mToast;

public void showToast(String text) {
  if (mToast == null) {
    mToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT);
  } else {
    mToast.setText(text);
    mToast.setDuration(Toast.LENGTH_SHORT);
  }
  mToast.show();
}

This method is no problem in older versions of android, when the new version is displayed for a short time while a Toast, will not be displayed.

Toast the same text and is currently being displayed, the system is considered wrong operation, so that the current display screen Toast request.

This problem is said to be done to prevent rogue app has a pop Toast imitate system interface leading to system collapse.

Solution

This is a limitation of the system, you want to get around this limitation can customize Toast, and here I recommend the god git on a custom version of Toast - XToast

https://github.com/getActivity/XToast

The article is not easy, if you liked this article, or you have a lot of hope that we help, thumbs up , forward , concerned  . Articles will be continuously updated. Absolutely dry! ! !

Guess you like

Origin blog.51cto.com/14775360/2485362