我一直在研究一个直接的文件管理器应用程序。我用于测试的设备是LG Nexus 4(v4.3)和Xperia x10i(v2.3.7)。 x10i的性能虽然有点迟缓,却没有问题。
轮换:
我跟踪了几个PopupWindows
。我使用标志来确定当前哪个PopupWindow
在屏幕上(目前,在任何给定时间,屏幕上最多只有一个PopupWindow)。在onSaveInstanceState(Bundle),
中,我使用Bundle
保存这些标记。在onCreate(Bundle)
中,我检索这些标记并在onPostExecute()
的{{1}}中使用它们。
问题:
如果在设备旋转时显示AsyncTask(called in onResume() and used for populating the ListView with data)
,则会销毁,重新创建活动,并再次显示PopupWindow
。这适用于两种设备。但是,今天,当搜索弹出窗口显示时,我将PopupWindow
从x10i
度旋转到90
度。该应用程序因以下异常而崩溃:
270
第2852行:
08-08 01:55:51.961: E/AndroidRuntime(32373): FATAL EXCEPTION: main
08-08 01:55:51.961: E/AndroidRuntime(32373): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.view.ViewRoot.setView(ViewRoot.java:544)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.view.Window$LocalWindowManager.addView(Window.java:424)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.widget.PopupWindow.invokePopup(PopupWindow.java:907)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.widget.PopupWindow.showAtLocation(PopupWindow.java:767)
08-08 01:55:51.961: E/AndroidRuntime(32373): at com.apprehension.phylerfilemanager.Phyler.showPopupSearch(Phyler.java:2852)
08-08 01:55:51.961: E/AndroidRuntime(32373): at com.apprehension.phylerfilemanager.Phyler$DisplayFilesTask.onPostExecute(Phyler.java:3453)
08-08 01:55:51.961: E/AndroidRuntime(32373): at com.apprehension.phylerfilemanager.Phyler$DisplayFilesTask.onPostExecute(Phyler.java:1)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.os.AsyncTask.finish(AsyncTask.java:417)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.os.AsyncTask.access$300(AsyncTask.java:127)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.os.Handler.dispatchMessage(Handler.java:99)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.os.Looper.loop(Looper.java:123)
08-08 01:55:51.961: E/AndroidRuntime(32373): at android.app.ActivityThread.main(ActivityThread.java:3701)
08-08 01:55:51.961: E/AndroidRuntime(32373): at java.lang.reflect.Method.invokeNative(Native Method)
08-08 01:55:51.961: E/AndroidRuntime(32373): at java.lang.reflect.Method.invoke(Method.java:507)
08-08 01:55:51.961: E/AndroidRuntime(32373): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
08-08 01:55:51.961: E/AndroidRuntime(32373): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
08-08 01:55:51.961: E/AndroidRuntime(32373): at dalvik.system.NativeStart.main(Native Method)
如果我每90度旋转并暂停,问题就不存在了。当设备经过180度旋转而没有暂停时发生崩溃。
保存标志:
popupWindowSearch.showAtLocation(popupViewSearch, Gravity.CENTER, 0, 0);
检索@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (searchPopup) {
outState.putBoolean("searchPopup", searchPopup);
outState.putString("searchKeyword", searchKeyword);
outState.putInt("searchType", searchType);
}
if (....) {
........
........
}
}
中的标记:
onCreate(Bundle)
从if (savedInstanceState != null) {
rotated = true;
if (savedInstanceState.containsKey("searchPopup")) {
searchPopup = true;
searchKeyword = savedInstanceState.getString("searchKeyword");
searchType = savedInstanceState.getInt("searchType");
}
....
....
}
执行AsyncTask
。在此onResume()
的{{1}}中:
onPostExecute()
在Nexus 4上进行测试时不会抛出异常。我还尝试将AsyncTask
发布到if (rotated) {
rotated = false;
if (searchPopup) {
showPopupSearch(searchType, searchKeyword); // Line 3453
}
....
....
} else {
searchPopup = false;
....
....
}
消息队列。问题依然存在。
我认为我处理屏幕旋转的方式存在问题。在我使用的应用程序中,屏幕旋转和布局更改顺利进行。在我的应用程序的情况下,您可以确切地告诉Runnable
被解雇并重新创建。大多数应用使用mContentView's (the activity's main view)
来处理屏幕旋转吗?我已经读过这种方法不正确。
答案 0 :(得分:2)
最有可能发生的是x10i正在进行两次Activity
实例化。这导致两个AsyncTasks
运行。第一个将最终引用Activity
的实例,在框架和窗口管理器的眼中,它不再存在(或应该存在),导致空令牌和结果异常。
在您的Activity#onStop
中,您应该设置AsyncTask#cancel
并在AsyncTask#onPostExecute
中检查是否已取消,如果是,则不会创建弹出窗口。
实际解决方案:
在Activity
中创建一个在onCreate()
中设置为false的标记。在onStop()
中将其设置为true,然后在onPostExecute
中检查是否已设置,如果是,则不显示弹出窗口。
答案 1 :(得分:0)
将PopupWindow显示为
final View parent = findViewById(R.id.{parentId});
parent.post(new Runnable() {
@Override
public void run() {
mPopup.showAtLocation(parent, ...);
}
});
解决了这个问题。