【问题标题】:Child activity thread causes the app to be frozen on suppression子活动线程导致应用程序在抑制时被冻结
【发布时间】:2016-04-07 16:42:08
【问题描述】:

我将我的代码组织如下:

MainMenu(一个活动)在Game(另一个活动)上启动一个意图。 Game 设置 GamePanel(表面保持器),以 GameThread(线程)开始。

MainMenu.java

public void buttonPlay(View view) {
    Intent intent = new Intent(this, Game.class);
    startActivity(intent);
}

Game.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(new GamePanel(this));
}

GamePanel.java

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
    gameThread = new GameThread(surfaceHolder, this);
    gameThread.setRunning(true);
    gameThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    gameThread.setRunning(false);
    try {
        gameThread.join();
        gameThread = null;
        } catch (InterruptedException e) { e.printStackTrace(); }
}

GameThread.java

@Override
public void run() {
    while (running) {
        frameDelay.setStart();
        canvas = null;
        try {
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder) {
                this.gamePanel.update();
                this.gamePanel.draw(canvas);
            }
        } catch (Exception e) { e.printStackTrace(); }
        finally {
            if (canvas != null) {
                try {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                } catch (Exception e) {e.printStackTrace();}
            }
        }
        try {
            sleep(frameDelay.setDelay());
        } catch (Exception e) { e.printStackTrace(); }
        frameDelay.displayFPS();
    }
    try {
        sleep(1000000);
    } catch (Exception e) { e.printStackTrace(); }
}

当我从Game 活动返回时出现问题。应用程序显示MainMenu 活动,但不再响应,很快系统要求终止它。除此之外,活动和线程运行良好。

我不知道是活动生命周期问题还是线程问题。当我根本不启动GameThread 时,应用程序运行良好。但是GamePanel surfaceDestroyed 被调用,所以我认为线程已正确停止。

我试着打电话:

  • Game onDestroy 抓住后退按钮。
  • Game 完成 抓住返回按钮。
  • Game onDestroyonPause
  • Game 完成onPause
  • 中断 GameThread。

以上方法都不能解决任何问题(有些会导致崩溃)。

当我打开应用程序并被杀死时,就会发生此错误:

E/WindowState(3143): Error happens during resized 
E/WindowState(3143): android.os.DeadObjectException
E/WindowState(3143):    at android.os.BinderProxy.transactNative(NativeMethod)
E/WindowState(3143):    at android.os.BinderProxy.transact(Binder.java:496)
E/WindowState(3143):    at android.view.IWindow$Stub$Proxy.resized(IWindow.java:333)
E/WindowState(3143):    at com.android.server.wm.WindowState.reportResized(WindowState.java:1420)
E/WindowState(3143):    at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:10129)
E/WindowState(3143):    at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:8887)
E/WindowState(3143):    at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:8829)
E/WindowState(3143):    at com.android.server.wm.WindowManagerService.access$400(WindowManagerService.java:164)
E/WindowState(3143):    at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:7782)
E/WindowState(3143):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/WindowState(3143):    at android.os.Looper.loop(Looper.java:135)
E/WindowState(3143):    at android.os.HandlerThread.run(HandlerThread.java:61)
E/WindowState(3143):    at com.android.server.ServiceThread.run(ServiceThread.java:46)

当应用没有响应时:

E/ActivityManager(3143): ANR in com.game.app (com.game.app/.MainMenu)
E/ActivityManager(3143): PID: 27828
E/ActivityManager(3143): Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago.  Wait queue length: 5.  Wait queue head age: 5534.6ms.)

编辑解决方案:

我终于找到问题了!它来自 GameThread 中我的 run 方法中的最后一次睡眠,删除它可以解决问题(并且不会因为它没有任何目的而错过)。如果有人可以解释毫秒如何导致应用程序完全冻结,请随意!

【问题讨论】:

  • 我添加了 Logcat。感谢您查看我的问题!
  • 你确定这个日志是你所有的吗?我想,应该还有更多。
  • 这是在我的应用程序上带有过滤器的 Logcat,我认为现在这是一个不好的做法,因为我没有看到系统显示的错误(我在帖子中添加了它)。我通过重复错误点来隔离它,它发生在我必须终止应用程序之前。我希望它缩小我的错误所在,我仍然没有看到解决方案......

标签: java android multithreading android-activity activity-lifecycle


【解决方案1】:

DeadObjectException 在调用死对象时发生。我怀疑你的线程在 onSurfaceDestroyed 发生时正在运行。您的线程使用surfaceholder 作为输入,如果它在被销毁时甚至调用一次,它可能会产生此错误。为什么你有一段时间的条件。如果它不满足并且线程在没有损坏的表面保持器的情况下运行怎么办。我看不到你的线程类,但我想你应该把 gameThread.setRunning(false);在while循环之前。

【讨论】:

  • 当线程运行时记录平均 FPS(Logcat 中的 30 倍数),当我退出时它停止执行。另外,我在此期间有一个日志,以确保已调用 join() (紧随其后)。因此,我假设线程已成功停止。
  • 现在有趣的是,我故意不停止线程,看看我是否会获得不同的行为并检验你的假设。这样做解决了冻结问题(太糟糕了,我现在有一个狂野的线程)!我没有看到链接,但至少我可以遵循一条线索......
  • 我放了一个while循环以防try块失败,以确保线程停止。不过,我不知道这是否是一种好习惯……而且对 setRunning() 方法的良好调用,我将其移出。谢谢你的建议!
  • 我现在这样做了,它似乎没有任何效果......如果我相信日志,无论如何它都会通过它一次,所以我认为它不会造成任何麻烦。
  • 因为我看不到其余的代码,所以很难说是什么原因。但关键是你可能在线程内部的某个地方调用了 dead surfaceholder。确保线程内的“运行”标志之外没有surfaceholder对象。所以当你设置running false时它不能调用holder。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 2010-09-20
  • 2021-05-10
  • 1970-01-01
相关资源
最近更新 更多