Android - Отправка ключей по тайм-ауту
В моем приложении для Android я получаю очень странный сбой, когда я нажимаю кнопку (изображение) на моем пользовательском интерфейсе, все приложение замерзает, и через пару секунд я получаю диалоговое окно с ужасной силой, появляющееся.
Вот что печатается в журнале:
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} [email protected] 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} [email protected] 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, вызвать проблему?
Любые другие идеи относительно того, что может быть причиной проблемы?
Ответы
Ответ 1
Вы должны быть как можно быстрее в своей реализации onClick. Дорогостоящие операции должны быть, вообще, выгружены в фоновый поток.
В onClick попробуйте:
Thread t = new Thread(){
public void run(){
your_stuff();
}
};
t.start();
вместо
your_stuff()
Ответ 2
Вы можете столкнуться с этой ошибкой, когда блокируете основной поток (a.k.a. поток пользовательского интерфейса) в течение нескольких секунд. Дорогостоящие операции должны быть, в общем, выгружены в фоновый поток. AsyncTask очень полезно в этих случаях.
В вашем случае вы можете сделать следующее:
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
serviceBinder.endCall(lineId);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}.execute();
Ответ 3
Если вы выполняете ресурсоемкую задачу, это может произойти. Возобновление деятельности.
1. Попробуйте остановить всю свою интенсивную работу onPause, а затем перезапустить его onResume.
2. Если вы показываете карту на наложении Activity activity, то прекратите обновление оверлеев во время сна. А затем перезапустите его onResume.
Ответ 4
Сделайте свою длинную операцию в отдельном потоке или используйте AsyncTask, чтобы избавиться от ANR.
А ANR (активность не отвечает) происходит при потоке long operation takes place in the "main"
. Это поток цикла событий, и если он занят, Android не может обработать какие-либо дополнительные события GUI в приложении и, таким образом, подбрасывает ANR dialog
.
Ваша деятельность заняла много времени, чтобы сказать Android OS "эй, я все еще жив"! (Это то, что делает поток пользовательского интерфейса).
http://developer.android.com/guide/practices/design/responsiveness.html
В принципе, если вы делаете поток пользовательского интерфейса выполняете сложную задачу, он слишком занят, делая свою задачу, чтобы сообщить ОС, что она все еще "жива".
http://android-developers.blogspot.co.uk/2009/05/painless-threading.html
Вы должны перенести свой XML-код Parsing в другой поток, затем использовать обратный вызов, чтобы сообщить, что поток пользовательского интерфейса вы закончили, и что-то сделать с результатом.
http://developer.android.com/resources/articles/timed-ui-updates.html
Обнаружение того, где происходят ANR, легко, если это постоянный блок (например, тупик, например, для некоторых замков), но сложнее, если это просто временная задержка. Во-первых, перейдите по своему коду и посмотрите на загружаемые места и длительные операции. Примеры могут включать использование сокетов, блокировок, спальных потоков и других операций блокировки из потока событий. Вы должны убедиться, что все это происходит в отдельных потоках. Если ничего не возникает, используйте DDMS и включите просмотр потока. Это показывает все потоки в вашем приложении, похожие на трассировку. Воспроизводите ANR и одновременно обновите основной поток. Это должно показать вам, что именно происходит во время ANR
Если Logcat не выводит ничего полезного, попробуйте вытащить traces.txt из /data/anr/traces.txt
adb pull /data/anr/traces.txt .
поскольку он может дать больше информации о том, где произошло исключение ANR
И эта ссылка также может быть полезна для создания AsyncTask и Threads