39

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

4 回答 4

50

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

在 onClick 中,尝试:

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

而不仅仅是

your_stuff()
于 2011-01-06T01:46:39.957 回答
5

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

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

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... params) {
        try {
            serviceBinder.endCall(lineId);
        } catch (RemoteException e) {
            e.printStackTrace();
        } 
    }
}.execute();
于 2012-10-04T00:38:12.413 回答
2

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

当某个线程发生ANR(Activity Not Responding) 。long operation takes place in the "main"这是事件循环线程,如果它很忙,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 Parsing 代码移动到另一个线程,然后使用回调告诉 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 异常发生位置的更多信息

这个链接也可能有助于创建 AsyncTask 和 Threads

于 2014-12-04T11:20:11.450 回答
1

If you are doing a resource intensive task then it might happen. While resuming the Activity. 1. Try stopping all your intensive work on onPause and then restarting it on onResume. 2. If you are showing map on Activity drawing overlay on it then stop refreshing the overlays while on sleep. And then restart it on onResume.

于 2013-10-15T11:24:44.913 回答