Android - 密钥调度超时

时间:2010-08-12 11:39:39

标签: android timeout key freeze dispatch

在我的Android应用程序中,我遇到了一个非常奇怪的崩溃,当我在我的UI上按下一个按钮(图像)时,整个应用程序冻结,几秒钟后我出现了可怕的强制关闭对话框。

以下是在日志中打印的内容:


WARN/WindowManager(88): Key dispatching timed out sending to package name/Activity
WARN/WindowManager(88): Dispatch state: {{KeyEvent{action=1 code=5 repeat=0 meta=0 scancode=231 mFlags=8} to Window{432bafa0 com.android.launcher/com.android.launcher.Launcher paused=false} @ 1281611789339 lw=Window{432bafa0 com.android.launcher/com.android.launcher.Launcher paused=false} lb=android.os.BinderProxy@431ee8e8 fin=false gfw=true ed=true tts=0 wf=false fp=false mcf=Window{4335fc58 package name/Activity paused=false}}}
WARN/WindowManager(88): Current state:  {{null to Window{4335fc58 package name/Activity paused=false} @ 1281611821193 lw=Window{4335fc58 package name/Activity paused=false} lb=android.os.BinderProxy@434c9bd0 fin=false gfw=true ed=true tts=0 wf=false fp=false mcf=Window{4335fc58 package name/Activity paused=false}}}
INFO/ActivityManager(88): ANR in process: package name (last in package name)
INFO/ActivityManager(88): Annotation: keyDispatchingTimedOut
INFO/ActivityManager(88): CPU usage:
INFO/ActivityManager(88): Load: 5.18 / 5.1 / 4.75
INFO/ActivityManager(88): CPU usage from 7373ms to 1195ms ago:
INFO/ActivityManager(88):   package name: 6% = 1% user + 5% kernel / faults: 7 minor
INFO/ActivityManager(88):   system_server: 5% = 4% user + 1% kernel / faults: 27 minor
INFO/ActivityManager(88):   tiwlan_wifi_wq: 3% = 0% user + 3% kernel
INFO/ActivityManager(88):   mediaserver: 0% = 0% user + 0% kernel
INFO/ActivityManager(88):   logcat: 0% = 0% user + 0% kernel
INFO/ActivityManager(88): TOTAL: 12% = 5% user + 6% kernel + 0% softirq
INFO/ActivityManager(88): Removing old ANR trace file from /data/anr/traces.txt
INFO/Process(88): Sending signal. PID: 1812 SIG: 3
INFO/dalvikvm(1812): threadid=7: reacting to signal 3
INFO/dalvikvm(1812): Wrote stack trace to '/data/anr/traces.txt'

这是Button(Image)的代码:


findViewById(R.id.endcallimage).setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        mNotificationManager.cancel(2);

                        Log.d("Handler", "Endcallimage pressed");

                        if(callConnected)
                        elapsedTimeBeforePause = SystemClock.elapsedRealtime() - stopWatch.getBase();

                        try {
                            serviceBinder.endCall(lineId);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        } 
                            dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.FLAG_SOFT_KEYBOARD));
                            dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
                    }
            });     

如果我评论以下内容,按下按钮(图像)不会导致崩溃:


try {
      serviceBinder.endCall(lineId);
    } catch (RemoteException e) {
      e.printStackTrace();
    } 

上面的代码调用了应用程序的几个级别并进入本机层(NDK),通过几个对象的调用是否会导致强制关闭?似乎不太可能,因为其他几个按钮也没有问题。

原生图层怎么样?我用NDK构建的一些代码是否会导致问题?

关于问题的原因可能是什么其他想法?

4 个答案:

答案 0 :(得分:45)

在onClick实现中,您必须尽可能快。通常,昂贵的操作应该卸载到后台线程。

在onClick上,尝试:

Thread t = new Thread(){
    public void run(){
        your_stuff();
    }
};
t.start();

而不仅仅是

your_stuff()

答案 1 :(得分:5)

当您阻止主线程(例如,UI线程)几秒钟时,您可能会遇到此错误。通常,昂贵的操作应该卸载到后台线程。 AsyncTask在这些情况下非常有用。

在您的情况下,您可以执行以下操作:

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... params) {
        try {
            serviceBinder.endCall(lineId);
        } catch (RemoteException e) {
            e.printStackTrace();
        } 
    }
}.execute();

答案 2 :(得分:2)

在单独的线程中执行长时间的操作或使用AsyncTask来摆脱ANR。

某些long operation takes place in the "main"主题时会发生 ANR(活动无响应)。这是事件循环线程,如果它很忙,Android无法处理应用程序中的任何进一步的GUI事件,因此会抛出ANR dialog

您的活动花了很长时间才对Android操作系统说'嘿,我还活着'! (这是UI线程的作用)。

http://developer.android.com/guide/practices/design/responsiveness.html

基本上,如果你让UI线程执行一些复杂的任务,它就会忙着告诉操作系统它仍然“活着”。

http://android-developers.blogspot.co.uk/2009/05/painless-threading.html

您应该将XML解析代码移动到另一个线程,然后使用回调告诉您已完成的UI线程并对结果执行某些操作。

http://developer.android.com/resources/articles/timed-ui-updates.html

如果ANR发生永久性阻塞(例如死锁获取某些锁定),则检测ANR发生的位置很容易,但如果它只是暂时的延迟则更难。首先,查看代码并查找可用的点和长时间运行的操作。示例可以包括在事件线程内使用套接字,锁,线程休眠和其他阻塞操作。你应该确保这些都发生在不同的线程中。如果没有任何问题,请使用DDMS并启用线程视图。这会显示应用程序中的所有线程与您拥有的跟踪类似。重现ANR,同时刷新主线程。这应该向你展示ANR时正在发生的事情

如果Logcat没有输出任何有用的内容,请尝试从/data/anr/traces.txt中提取traces.txt

adb pull /data/anr/traces.txt .

因为它可能会提供有关ANR异常发生位置的更多信息

this link也可能有助于创建AsyncTask和Threads

答案 3 :(得分:1)

如果您正在执行资源密集型任务,则可能会发生这种情况。在恢复活动的同时。  1.尝试停止onPause上的所有密集工作,然后在onResume上重新启动它。  2.如果要在其上显示活动图形覆盖图上的地图,则在休眠时停止刷新叠加层。然后在onResume上重新启动它。