关于java.lang.IllegalArgumentException: View not attached to window manager 错误的分析

本文主要是介绍关于java.lang.IllegalArgumentException: View not attached to window manager 错误的分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天遇到一个很奇特的问题,当用户设置了PIN码,在锁屏界面正常解锁PIN码后,进入Launcher时显示com.android.phone 已停止运行。一开始猜想会不会是解锁PIN码的时候处理导致了Phone进程报错,通过log分析找到了问题的大概原因:

[plain]  view plain copy
  1. AndroidRuntime: FATAL EXCEPTION: main  
  2. AndroidRuntime: java.lang.IllegalArgumentException: View not attached to window manager  
  3. AndroidRuntime:     at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:385)  
  4. AndroidRuntime:     at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:287)  
  5. AndroidRuntime:     at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:79)  
  6. AndroidRuntime:     at android.app.Dialog.dismissDialog(Dialog.java:323)  
  7. AndroidRuntime:     at android.app.Dialog.dismiss(Dialog.java:306)  
  8. AndroidRuntime:     at com.android.stk.StkDialogActivity$4.onClick(StkDialogActivity.java:188)  
  9. AndroidRuntime:     at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:169)  
  10. AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:99)  
  11. AndroidRuntime:     at android.os.Looper.loop(Looper.java:153)  
  12. AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5299)  
  13. AndroidRuntime:     at java.lang.reflect.Method.invokeNative(Native Method)  
  14. AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:511)  
  15. AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)  
  16. AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)  
  17. AndroidRuntime:     at dalvik.system.NativeStart.main(Native Method)  


转载请务必注明出处:http://blog.csdn.net/yihongyuelan

通过分析PIN码的解锁流程知道,并不是PIN码解释时的dialog导致的问题。PIN码解锁流程另用文档说明。
仔细查看log后发现有:
[plain]  view plain copy
  1. AndroidRuntime:     at com.android.stk.StkDialogActivity$4.onClick(StkDialogActivity.java:188)  
       这是开机识别到SIM卡之后弹出的STK对话框。那为什么会报com.android.phone已停止运行呢?

       经过以上分析,我们可以大致猜测是因为STK引起的问题,既然是STK的问题那为什么会报phone的错误呢?如果是phone的错误那么从log中应该可以检索到phone相关的问题,为什么没有呢?那么我们接下来一一解答这些问题。

(1). 为什么报错com.android.phone已停止运行?

通过查看STK的源码(单卡MTK的代码在/mediatec/packages/app/stk1),在其AndroidManifest.xml可以发现:
android:sharedUserId="android.uid.phone"
也就是STK和Phon在一个进程中,因此在报错的表现上来讲就会是com.andorid.phone。

(2). 为什么会报View not attached to window manager错误?

这个错误的意思是说我们所操作的View没有被纳入window manager的管理。
我们知道所有的窗口创建和管理都是依附于window manager的,因此Dialog的创建也不例外。Dialog的创建流程通过查看源码可以知道,在Dialog的构造函数中,创建了一个Window对象,但我们知道Window对象并不是用于显示的,真正用于显示的是View对象。因此通过Dialog的show方法构造了一个mDecor的View对象,并最终通过WindowManager的addView()方法显示Dialog。
通过查看log信息我们可以看到com.android.stk.StkDialogActivity$4.onClick(StkDialogActivity.java:188)
查看对应的StkDialogActivity代码后发现,在188行处代码为dialog.dismiss();
在网络上搜索后发现,多数情况下出现这种错误,都是在dismiss Dialog时,发现创建该Dialog的Activity存在而导致的。
比如在界面上显示一个Dialog,当任务处理结束后再Dismiss Dialog。如果在Dialog显示期间,该Activity因为某种原因被杀掉且又重新启动了,那么当任务结束时,Dismiss Dialog的时候WindowManager检查,就会发现该Dialog所属的Activity已经不存在了(重新启动了一次,是一个新的Activity),所以会报IllegalArgumentException: View not attached to window manager.
通过以上分析我们可以知道在STK Dialog在执行dismiss方法时,发现启动它的Activity已经不见了,被杀掉了(现在这个是重新启动的),所以才报错出现异常。

(3). 为什么STKDialogActivity会被"杀掉"?

通过跟踪查看异常log我们可以看到StkDialogActivity的生命周期打印log如下:
[plain]  view plain copy
  1. onCreate  
  2. onResume - mbSendResp[false], sim id: 0  
  3. ... ...省略部分  
  4. onSaveInstanceState  
  5. onPause, sim id: 0  
  6. ... ...省略部分  
  7. onDestroy-  
  8. onCreate  
  9. ... ...省略部分  
  10. onRestoreInstanceState - [com.android.internal.telephony.cat.TextMessage@41fe7d80]  
  11. onResume - mbSendResp[false], sim id: 0  
到这里后就出现了异常错误……
通过log我们可以很清楚的看到该Activity启动了两次。在log中我们也看到了onSaveInstanceState方法。
对于onSaveInstanceState方法,在Android SDK里面有这样的描述:
Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key)
也就说当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
注意这里的容易二字,当前Activity并没有被销毁,只是系统觉得它有可能会被销毁因此会执行该方法。在该方法中我们可以保存Activity中的各种数据信息,如果该Activity真的被杀掉而又重新启动后,可以使用onRestoreInstanceState方法在重新启动该Activity时,还原我们之前保存的数据信息。onSaveInstanceState方法的调用遵循一个重要原则,即当系统“未经你许可”销毁了你的Activity时,onSaveInstanceState就会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然如果你自己不保存,那就没法恢复了)。
因此通过以上分析我们可以看到STKDialogActivity的确被杀掉后再次启动了,但为什么会被杀掉,通过log并没有找到答案。

(4). 在STKDialogActivity被杀掉时,Dialog存在么?

       可能大家会有疑问,Dialog都没有看到,就出现错误了,怎么能确定该Dialog当时一定是显示的呢?继续在log中搜索我们可以发现:
[plain]  view plain copy
  1. WindowManager: Activity com.android.stk.StkDialogActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{41fea228 V.E..... R.....ID 0,0-1026,433} that was originally added here  
  2. WindowManager: android.view.WindowLeaked: Activity com.android.stk.StkDialogActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{41fea228 V.E..... R.....ID 0,0-1026,433} that was originally added here  
  3. WindowManager:  at android.view.ViewRootImpl.<init>(ViewRootImpl.java:409)  
  4. WindowManager:  at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:218)  
  5. WindowManager:  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)  
  6. WindowManager:  at android.app.Dialog.show(Dialog.java:281)  
  7. WindowManager:  at android.app.AlertDialog$Builder.show(AlertDialog.java:951)  
  8. WindowManager:  at com.android.stk.StkDialogActivity.onCreate(StkDialogActivity.java:192)  
  9. WindowManager:  at android.app.Activity.performCreate(Activity.java:5122)  
  10. WindowManager:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081)  
  11. WindowManager:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270)  
  12. WindowManager:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2358)  
  13. WindowManager:  at android.app.ActivityThread.access$600(ActivityThread.java:156)  
  14. WindowManager:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1340)  
  15. WindowManager:  at android.os.Handler.dispatchMessage(Handler.java:99)  
  16. WindowManager:  at android.os.Looper.loop(Looper.java:153)  
  17. WindowManager:  at android.app.ActivityThread.main(ActivityThread.java:5299)  
  18. WindowManager:  at java.lang.reflect.Method.invokeNative(Native Method)  
  19. WindowManager:  at java.lang.reflect.Method.invoke(Method.java:511)  
  20. WindowManager:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)  
  21. WindowManager:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)  
  22. WindowManager:  at dalvik.system.NativeStart.main(Native Method)  
       这里的WindowManager报错是什么意思呢? 这段log是WindowManager抛出的error错误,当我们的Dialog还没有dismiss时,如果此时该Activity被销毁了,那么就会出现以上错误,提示窗口泄漏(leaked window)。这里自己也做了一个实验,写一个demo,在Activity的onCreate方法中显示一个Dialog,然后直接调用finish方法。代码大致如下:
[java]  view plain copy
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.     super.onCreate(savedInstanceState);  
  3.     setContentView(R.layout.activity_main);  
  4.     AlertDialog.Builder info = new Builder(this);  
  5.     info.setTitle("Dialog").setPositiveButton("OK"null).setMessage("This is a Dialog");;  
  6.     info.show();   
  7.     finish();  
  8. }  
       直接将此程序run到模拟器或者真机上,查看log我们就能看到leaked window的报错信息。因此这也证明了前面我们的假设,即StkActivity在被销毁时,其所依附的 Dialog是存在的。

(5). 如何解决这个问题呢?

通过以上分析之后我们知道了问题出现的原因,那么如何解决呢?可以通过以下两个方面来解决:
1. 使用Activity自带的Dialog控制方法
在Activity中需要使用对话框,可以使用Activity自带的回调,比如onCreateDialog(),showDialog(),dimissDialog(),removeDialog()等等。毕竟这些都是Activity自带的方法,所以用起来更方便,也不用显示创建和操控Dialog对象,一切都由框架操控,相对来说比较安全。
2. 限制Dialog的生命周期
让创建的Dialog对象的存活周期跟Activity的生命周期一致,也就是说Dialog的生命周期被限定在Activity的onCreate()和onDestroy()方法之间。

这篇关于关于java.lang.IllegalArgumentException: View not attached to window manager 错误的分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/856763

相关文章

JVisualVM之Java性能监控与调优利器详解

《JVisualVM之Java性能监控与调优利器详解》本文将详细介绍JVisualVM的使用方法,并结合实际案例展示如何利用它进行性能调优,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1. JVisualVM简介2. JVisualVM的安装与启动2.1 启动JVisualVM2

Java如何从Redis中批量读取数据

《Java如何从Redis中批量读取数据》:本文主要介绍Java如何从Redis中批量读取数据的情况,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一.背景概述二.分析与实现三.发现问题与屡次改进3.1.QPS过高而且波动很大3.2.程序中断,抛异常3.3.内存消

SpringBoot使用ffmpeg实现视频压缩

《SpringBoot使用ffmpeg实现视频压缩》FFmpeg是一个开源的跨平台多媒体处理工具集,用于录制,转换,编辑和流式传输音频和视频,本文将使用ffmpeg实现视频压缩功能,有需要的可以参考... 目录核心功能1.格式转换2.编解码3.音视频处理4.流媒体支持5.滤镜(Filter)安装配置linu

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

在Spring Boot中实现HTTPS加密通信及常见问题排查

《在SpringBoot中实现HTTPS加密通信及常见问题排查》HTTPS是HTTP的安全版本,通过SSL/TLS协议为通讯提供加密、身份验证和数据完整性保护,下面通过本文给大家介绍在SpringB... 目录一、HTTPS核心原理1.加密流程概述2.加密技术组合二、证书体系详解1、证书类型对比2. 证书获

Java使用MethodHandle来替代反射,提高性能问题

《Java使用MethodHandle来替代反射,提高性能问题》:本文主要介绍Java使用MethodHandle来替代反射,提高性能问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录一、认识MethodHandle1、简介2、使用方式3、与反射的区别二、示例1、基本使用2、(重要)

Java实现本地缓存的常用方案介绍

《Java实现本地缓存的常用方案介绍》本地缓存的代表技术主要有HashMap,GuavaCache,Caffeine和Encahche,这篇文章主要来和大家聊聊java利用这些技术分别实现本地缓存的方... 目录本地缓存实现方式HashMapConcurrentHashMapGuava CacheCaffe

SpringBoot整合Sa-Token实现RBAC权限模型的过程解析

《SpringBoot整合Sa-Token实现RBAC权限模型的过程解析》:本文主要介绍SpringBoot整合Sa-Token实现RBAC权限模型的过程解析,本文给大家介绍的非常详细,对大家的学... 目录前言一、基础概念1.1 RBAC模型核心概念1.2 Sa-Token核心功能1.3 环境准备二、表结

eclipse如何运行springboot项目

《eclipse如何运行springboot项目》:本文主要介绍eclipse如何运行springboot项目问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目js录当在eclipse启动spring boot项目时出现问题解决办法1.通过cmd命令行2.在ecl

Java中的Closeable接口及常见问题

《Java中的Closeable接口及常见问题》Closeable是Java中的一个标记接口,用于表示可以被关闭的对象,它定义了一个标准的方法来释放对象占用的系统资源,下面给大家介绍Java中的Clo... 目录1. Closeable接口概述2. 主要用途3. 实现类4. 使用方法5. 实现自定义Clos