3

我一直在开发一个简单的文件管理器应用程序。我用于测试的设备是 LG Nexus 4 (v4.3) 和 Xperia x10i (v2.3.7)。x10i 的性能虽然有点迟钝,但没有问题。

旋转时:

有几个PopupWindows我跟踪。我使用标志来确定PopupWindow当前在屏幕上的是哪个(目前,在任何给定时间最多有一个 PopupWindow 在屏幕上)。在onSaveInstanceState(Bundle),我使用Bundle. 在onCreate(Bundle)中,我检索这些标志并onPostExecute()AsyncTask(called in onResume() and used for populating the ListView with data).

问题:

如果PopupWindow在设备旋转时显示 a,则活动将被销毁,重新创建,然后PopupWindow再次显示。这在两种设备上都运行良好。但是,今天,当搜索弹出窗口显示时,我x10i90度数旋转到度数。270该应用程序因以下异常而崩溃:

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)

第 2852 行:

popupWindowSearch.showAtLocation(popupViewSearch, Gravity.CENTER, 0, 0);    

如果我每 90 度旋转并暂停一次,则问题不存在。当设备在没有暂停的情况下进行 180 度旋转时,就会发生崩溃。

保存标志:

@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");
    }

    ....
    ....
}

AnAsyncTask从 执行onResume()。在onPostExecute()这个AsyncTask

if (rotated) {
    rotated = false;
    if (searchPopup) {
        showPopupSearch(searchType, searchKeyword);     // Line 3453                        
    }
    ....
    ....
} else {
    searchPopup = false;
    ....
    ....
}

在 Nexus 4 上进行测试时不会引发异常。我也尝试过发布RunnablemContentView's (the activity's main view)消息队列。问题仍然存在。

我认为我处理屏幕旋转的方式存在问题。在我使用过的应用程序中,屏幕旋转和布局变化发生得很顺利。在我的应用程序中,您可以从字面上看出PopupWindow正在被解雇和重新创建。大多数应用程序是否使用 处理屏幕旋转android:configChanges="keyboardHidden|orientation|screenSize"?我读过这种方法是不正确的。

4

2 回答 2

2

最有可能发生的是 x10i 正在执行两个Activity实例化。这导致两个AsyncTasks运行。第一个最终将引用一个Activity在框架和窗口管理器眼中不再存在(或应该存在)的实例,从而导致空标记和结果异常。

在您中Activity#onStop,您可能应该设置AsyncTask#cancelAsyncTask#onPostExecute检查它是否已取消,如果是,请不要创建弹出窗口。


实际解决方案:

在 中创建一个Activity设置为 false的标志onCreate()。将其设置为onStop()true,然后onPostExecute检查它是否已设置,如果已设置,则不显示弹出窗口。

于 2013-08-08T06:42:45.497 回答
0

将 PopupWindow 显示为

final View parent = findViewById(R.id.{parentId});
parent.post(new Runnable() {
    @Override
    public void run() {
        mPopup.showAtLocation(parent, ...);
    }
});

已经解决了这个问题。

于 2014-08-23T17:02:33.207 回答