代码之家  ›  专栏  ›  技术社区  ›  Donal Rafferty

Android-密钥调度超时

  •  34
  • Donal Rafferty  · 技术社区  · 14 年前

    在我的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'
    


    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 回复  |  直到 14 年前
        1
  •  48
  •   juanes    12 年前

    在onClick实现中必须尽可能快。一般来说,昂贵的操作应该卸载到后台线程。

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

    而不仅仅是

    your_stuff()
    
        2
  •  5
  •   juanes    12 年前

    AsyncTask 在这些情况下非常有用。

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

    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                serviceBinder.endCall(lineId);
            } catch (RemoteException e) {
                e.printStackTrace();
            } 
        }
    }.execute();
    
        3
  •  2
  •   Community kfsone    7 年前

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

    ANR(活动无响应) 当一些 long operation takes place in the "main" 线程。这是事件循环线程,如果它很忙,Android将无法处理应用程序中的任何GUI事件,从而抛出一个错误消息 ANR dialog .

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

    基本上,如果让UI线程执行一些复杂的任务,那么它就太忙了,无法告诉OS它仍然是“活动的”。

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

    您应该将XML解析代码移动到另一个线程,然后使用回调来告诉UI线程您已经完成并对结果进行处理。

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

    如果是一个永久性的块(比如获取一些锁的死锁),检测ANRs发生的位置很容易,但是如果只是一个临时的延迟,检测ANRs发生的位置就更难了。首先,检查您的代码并查找易受攻击的点和长时间运行的操作。示例可能包括在事件线程内使用套接字、锁、线程休眠和其他阻塞操作。你应该确保这些都发生在不同的线程中。如果没有问题,请使用DDMS并启用线程视图。这将显示应用程序中与跟踪类似的所有线程。复制ANR,同时刷新主线程。这应该能准确地告诉你在ANR的时候发生了什么

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

    adb pull /data/anr/traces.txt .
    

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

    以及 this link 也可能有助于创建异步任务和线程

        4
  •  1
  •   Rajesh Narwal    11 年前

    如果你正在做一个资源密集型的任务,那么它可能会发生。在恢复活动的同时。 2如果在活动中显示地图,则在睡眠时停止刷新覆盖图。然后在恢复时重新启动。