Android - тайм-аут отправки ключей - PullRequest
35 голосов
/ 12 августа 2010

В моем приложении для 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} 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 ]

46 голосов
/ 06 января 2011

Вы должны быть максимально быстрыми в своей реализации onClick. Обычно дорогостоящие операции должны быть выгружены в фоновый поток.

В onClick, попробуйте:

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

вместо

your_stuff()
5 голосов
/ 04 октября 2012

Вы можете столкнуться с этой ошибкой, когда вы блокируете основной поток (он же поток пользовательского интерфейса) на несколько секунд.В общем случае дорогостоящие операции должны быть выгружены в фоновый поток. AsyncTask очень полезен в этих случаях.

В вашем случае вы можете сделать следующее:

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... params) {
        try {
            serviceBinder.endCall(lineId);
        } catch (RemoteException e) {
            e.printStackTrace();
        } 
    }
}.execute();
2 голосов
/ 04 декабря 2014

Выполняйте длинную операцию в отдельном потоке или используйте AsyncTask, чтобы избавиться от ANR.

ANR (активность не отвечает) происходит, когда какой-то поток long operation takes place in the "main". Это поток цикла событий, и если он занят, Android не может обрабатывать какие-либо дальнейшие события графического интерфейса в приложении и, следовательно, выдает ANR dialog.

Ваша активность заняла много времени, чтобы сказать ОС Android: «Эй, я все еще жив»! (Это то, что делает поток пользовательского интерфейса).

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

По сути, если вы заставляете поток пользовательского интерфейса выполнять какую-то сложную задачу, он слишком занят выполнением вашей задачи, чтобы сказать ОС, что он все еще "жив".

http://android -developers.blogspot.co.uk / 2009/05 / безболезненным-threading.html

Вам следует переместить код синтаксического анализа XML в другой поток, а затем использовать обратный вызов, чтобы сообщить завершившемуся потоку пользовательского интерфейса и что-то сделать с результатом.

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

1 голос
/ 15 октября 2013

Если вы выполняете ресурсоемкую задачу, это может произойти. При возобновлении деятельности. 1. Попробуйте прекратить всю интенсивную работу с onPause, а затем перезапустите на onResume. 2. Если вы показываете карту на наложении «Рисование активности», прекратите обновление наложений во время сна. А затем перезапустите его на onResume.

...