记一次使用windowManager addview()的token为null的历程

最近想了解一下android的悬浮窗是怎么实现的,然后就进行了尝试。

在activity中执行下面这段代码是可行的。

WindowManager windowManager = getSystemService(WindowManager.class);

Button button =new Button(this);

button.setText("111");

WindowManager.LayoutParams layoutParams =new WindowManager.LayoutParams();

layoutParams.width =100;

layoutParams.height =100;

layoutParams.gravity =Gravity.CENTER;

windowManager.addView(button,layoutParams);

在windowManager中直接添加view。正常执行,但是在Application的onCreate方法中执行,或者在Service的onCreate

方法中执行都会报错: Caused by: android.view.WindowManager$BadTokenException:

 Unable to add window -- token null is not valid; is your activity running?



然后就想着怎么样去解决这个错误,一开始以为是没有token。 就去翻阅Toast的show方法实现流程。发现

Toast的 layoutParams.token=windowToken。然后就去查看windowToken是怎么创建的,得出结论是Binder token =new Binder();这样直接创建的并没有什么特殊的。然后我又进行了尝试:

WindowManager windowManager = getSystemService(WindowManager.class);

Button button =new Button(this);

button.setText("111");

WindowManager.LayoutParams layoutParams =new WindowManager.LayoutParams();

layoutParams.width =100;

layoutParams.height =100;

layoutParams.gravity =Gravity.CENTER;

layoutParams.token =new Binder();//这里添加了一个自己创建的token。

windowManager.addView(button,layoutParams);

上面的代码在application的onCreate方法和service的onCreate方法中执行,还是报了上面的错。这就遭难了......



以前知道layoutParams.type这个变量是控制视图层级的,但是也一直没有很深入的了解每个层级对应的值是哪些,因为报错是说token为Null

也没往这个type上想。后面进行了网上搜索之后,发现一些网友的说法这个type很重要。然后就尝试给type进行赋值。代码修改如下:

WindowManager windowManager = getSystemService(WindowManager.class);

Button button =new Button(this);

button.setText("111");

WindowManager.LayoutParams layoutParams =new WindowManager.LayoutParams();

layoutParams.width =100;

layoutParams.height =100;

layoutParams.gravity =Gravity.CENTER;

//layoutParams.type =WindowManager.LayoutParams.TYPE_PHONE; //这个值报错了 说没有权限,因为现实悬浮窗需要系统权限。

//layoutParams.type =WindowManager.LayoutParams.TYPE_TOAST; //这个值报错了 说没有权限,因为现实悬浮窗需要系统权限。

windowManager.addView(button,layoutParams);

总结:经过上面的两次修改还是不能成功运行,但是它没有报token为null的异常错误了,这是好事。那接下来就是对这个type的值的尝试了。


layoutParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;这个值加上之后就能正常添加view了

最后经过尝试,发现type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;这个值是可以在除activity外正常运行的,其他的试了好几个也不行。所以以后如果能满足需求就直接使用这个type。如果不能满足再尝试其他的吧。这个值是添加的view会在应用的上表层显示。

在application的onCreate方法或者在service的onCreate方法里面运行下面代码是正常的。

WindowManager windowManager = getSystemService(WindowManager.class);

Button button =new Button(this);

button.setText("111");

WindowManager.LayoutParams layoutParams =new WindowManager.LayoutParams();

layoutParams.width =100;

layoutParams.height =100;

layoutParams.gravity =Gravity.CENTER;

layoutParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; //这个type是可以正常运行的

windowManager.addView(button,layoutParams);

至此:我们就能通过windowManager去添加view了。

同时解决了两个异常:

异常1:Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@e856f1c -- permission denied for window type 2999

异常2: Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

最后总结:layoutParams.type的值还是非常重要的,如果能把所有的type值理解透就舒服了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容