Question:

The Toast of the system will no longer be displayed when the user disables the message notification in the 5.0 + system.

The reason: Toast by NotificationManagerService maintain a Toast queue, and then inform call WindowManager add view, so when the user closes the notification authority, NotificationManagerService affected, Toast cannot be displayed.

Solutions to consider:

1, modelled on the Toast then use Handler + Queue own message Queue to maintain, let it not influenced by NotificationManagerService, display or use the WindowManager to addview

WindowManager addView, although TYPE_TOAST is selected on MIUI 8, it is still not displayed if the permission is not enabled

2. Write a custom notification via Dialog, PopupWindow.

Contrary to the original purpose of toast, toasts do not get focus, but dialog and PopupWindow do and cover up the content below.

Add a View by going directly to the outermost content layout of the current page.

You need to pass the activity to get the outermost content; And when a dialogFragment is overwritten, the view added through the activity’s content will be overwritten by the dialogFragment.

The method adopted in this paper

In this paper, the third method is adopted to obtain the current outermost ViewGroup and display Toast through the ViewGroup AddView, which solves the problem mentioned above.

1. The use method needs to be initialized first:

SHToast.init(new SHToast.ToastListener() {

@Override

public Activity getCurrentActivity() {

return ActivityLifecycleCallbacks.getInstance().getResumeActivity();

}

});

Copy the code

And then you can use it like Toast,

MakeText (context, "default Toast style ",

SHToast.LENGTH_SHORT).show();



Copy the code

Or just call

(" Test test ");

Copy the code

If not initialized, it can be called

Toast. Toast (activity, "test test ");

Copy the code

See source code: SHToast

2. Implementation principle

  • First, message queues are maintained using Handler+Queue.
  • The incoming activity needs to be called at initialization time:
    SHToast.init(new SHToast.ToastListener() {

    @Override

    public Activity getCurrentActivity() {

    return ActivityLifecycleCallbacks.getInstance().getResumeActivity();

    }

    });

    Copy the code

    In ActivityLifecycleCallbacks I maintain a list of the activity, can obtain the activity of current resume.

    ActivityLifecycleCallbacks implemented Application. ActivityLifecycleCallbacks

If there is no activity resume, the toast is not displayed.

  • To solve the problem of dialogFragment coverage, the key process is how to obtain the outermost viewgroup.
    • Check whether there is an Android.app. Fragment appFragment. If there is an Android.app. Fragment appFragment, loop until the outermost ViewGroup is retrieved, and then retrieve the Content element

      container = rootView.findViewById(android.R.id.content);

      If not, go to the next step;
    • And then judge whether there is a visible android. Support. V4. App. Fragments, in the same way, if you have, cycle until the outermost ViewGroup, then obtain the content element

      container = rootView.findViewById(android.R.id.content);

      If not, go to the next step;
    • Get the outermost viewGroup of the activity,

      container = (ViewGroup) activity.findViewById(android.R.id.content);

    The key codes are as follows:

private static boolean initToastView(Activity activity, ToastMsg msg) {

if (null == activity) {

return false;

}

FragmentActivity fragmentActivity;

android.support.v4.app.Fragment visibleFragment = null;

android.app.Fragment appFragment = null;

Bundle bundle = new Bundle();

bundle.putInt("key", 0);

try {

appFragment = activity.getFragmentManager().getFragment(bundle, "key");

} catch (Exception e) {



}

if (null ! = appFragment) {

View rootView = appFragment.getView();

ViewParent viewParent = null;

while (null ! = rootView.getParent()) {

viewParent = rootView.getParent();

if (null ! = viewParent && viewParent instanceof ViewGroup) {

rootView = (ViewGroup) viewParent;

} else {

break;

}

}

container = (ViewGroup) rootView.findViewById(android.R.id.content);

}



if (null == container) {

if (activity instanceof FragmentActivity) {

fragmentActivity = (FragmentActivity) activity;

List<android.support.v4.app.Fragment> fragments = fragmentActivity.getSupportFragmentManager().getFragments();

if (null ! = fragments) {

for (android.support.v4.app.Fragment fragment : fragments) {

if (fragment ! = null && fragment.getUserVisibleHint()) {

visibleFragment = fragment;

break;

}

}

}

}

if (null ! = visibleFragment) {

View rootView = visibleFragment.getView();

container = (ViewGroup) rootView.findViewById(android.R.id.content);

}

}



if (null == container) {

container = (ViewGroup) activity.findViewById(android.R.id.content);

}



if (null == container) {

return false;

}



...

return true;

}

Copy the code