在我的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构建的一些代码是否会导致问题?
关于问题的原因可能是什么其他想法?
答案 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上重新启动它。