Как устранить ошибку ANR при вызове камеры? - PullRequest
3 голосов
/ 17 декабря 2011

У меня есть две кнопки в главном меню.Я вызываю камеру, когда нажимаю 1-ю кнопку.Здесь я не получил никаких проблем.Камера работает нормально.Сделав снимок, я возвращаюсь в главное меню и снова нажимаю 1-ю кнопку.Здесь я получил вопрос.Камера вызывается правильно.Но я получил ANR error (Reason: keyDispatchingTimedOut) пока делаю снимок.Как решить эту проблему?

Редактировать ::

Я использую следующий код,

Button Listener ,

Button imageButton = (Button) findViewById(R.id.button1);
imageButton.setOnClickListener(new  View.OnClickListener() {

    public void onClick(View arg0) {
    Intent intent = new Intent();
    intent.setClass(activity, ImageActivity.class);
    startActivity(intent);
    }
});

ImageActivity.java

public class ImageActivity extends Activity implements SurfaceHolder.Callback {
    private Camera camera = null;
    private SurfaceHolder surfaceHolder = null;
    private boolean previewRunning = false;
    private Button btnDone, btnCapture, btnRetake;
    private Bitmap mBitmap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.surface_screen);
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceHolder.setFixedSize(getWindow().getWindowManager()
                .getDefaultDisplay().getWidth(), getWindow().getWindowManager()
                .getDefaultDisplay().getHeight());
        LayoutInflater  controlInflater = LayoutInflater.from(getBaseContext());

        final View viewControl = controlInflater.inflate(R.layout.control, null);
        LayoutParams layoutParamsControl = new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        activity.addContentView(viewControl, layoutParamsControl);

        btnCapture = (Button) findViewById(R.id.takepicture);

        btnDone = (Button) findViewById(R.id.send);

        btnCapture.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                camera.takePicture(null, picCalBac, picCalBac);
            }
        });


    Camera.PictureCallback picCalBac = new PictureCallback() {

        public void onPictureTaken(byte[] data, Camera camera) {
            if (data != null) {
                mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            }
        }
    };

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        if (previewRunning) {
            camera.stopPreview();
        }
        try {
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            Log.d("IOException", e.getMessage());
        }
        camera.startPreview();
        previewRunning = true;
    }

    public void surfaceCreated(SurfaceHolder arg0) {
        camera = Camera.open(0);
    }

    public void surfaceDestroyed(SurfaceHolder arg0) {
        camera.stopPreview();
        previewRunning = false;
        camera.release();
    }
}

Ответы [ 5 ]

9 голосов
/ 19 декабря 2011

Возможно, вы просматривали эту ссылку во время поиска ошибки.

Хотя у меня никогда не было такой проблемы, после прочтения в Интернете это я понимаю:

Описание:

При выполнении процесса возникает ошибка ANR или приложение не отвечает на основной поток занимает слишком много времени (что-то вроде> 5 секунд). Android убивает этот процесс и любые связанные с ним по конструкции, чтобы сэкономить устройства ресурсы.

Решение состоит в том, чтобы запускать дорогостоящие задачи в другом потоке, и затем отправьте сообщение или обновите основную ветку соответственно.

См. Это: Клавиша ANR AndroidОтправкаВремя выключено

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

Так что лучше классифицируйте свой код, пишите каждую новую задачу по-разному Thread,Handler и, если вы выполняете задачу пользовательского интерфейса, используйте runOnUIThread. Async Task тоже очень удобно.

Другое дело - попытаться убрать зависимость кода от других. Запишите некоторые значения по умолчанию, и тогда вы сможете отправить пользователя обратно к первому заданию, если оно выполнено неправильно.

Я считаю, что ошибка связана с вашим стилем кодирования, а не с какой-либо конкретной ошибкой в ​​вашем коде.

Вам нужно улучшить этот конкретный код, чтобы он работал эффективно, и для этого посмотрите эти 2 ссылки:

  1. Дизайн для отзывчивости
  2. Безболезненная резьба

EDIT:

Это я где-то читал и нашел эффективным,

Как исследовать ANR?

Во-первых, просмотрите код и найдите уязвимые места и длительные операции. Примеры могут включать в себя использование сокетов, блокировок, спящих потоков и других операций блокировки из потока событий. Вы должны убедиться, что все это происходит в отдельных потоках. Если ничто не кажется проблемой, используйте DDMS и включите представление потока. Это показывает все потоки в вашем приложении, похожие на след, который вы имеете. Воспроизведите ANR и обновите основной поток одновременно. Это должно показать вам точно, что происходит во время ANR

Также если ANR вызван из-за потоков?

вы можете использовать Сервис для этого, Таким образом, ваше приложение может выполнять трудоемкие задачи внутри service.onStart (), передача данных (например) в намерении, используемом для запуска службы.

Однако службы выполняются в главном потоке приложений. Если отдельный нужен поток, он может быть создан сервисом внутри onStart ().

Уже есть встроенный класс, который делает это: IntentService

Также найдено одно полезное библиотечное приложение SalomonBrys / ANR-WatchDog

6 голосов
/ 19 декабря 2011

Android applications normally run entirely on a single (i.e. main) thread. Это означает, что все, что ваше приложение делает в основном потоке, для выполнения которого long time может вызвать ANR dialog, потому что ваше приложение не дает себе возможности обработать input event или I ntent broadcast. Так что В этом случае вы можете использовать StrictMode, чтобы помочь найти потенциально длительные операции, такие как операции с сетью или базой данных, которые вы могли бы случайно выполнять в основном потоке. Если вы обнаружите нарушения, которые, по вашему мнению, являются проблематичными, существует множество инструментов, помогающих их устранить: threads, Handler, AsyncTask, IntentService и т. Д. Также следует помнить, что они возникли из API Level 9

Пример кода для включения с самого начала в Application, Activity или другом методе onCreate() другого компонента приложения:

 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()   // or .detectAll() for all detectable problems
                 .penaltyLog()
                 .build());
         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                 .detectLeakedSqlLiteObjects()
                 .detectLeakedClosableObjects()
                 .penaltyLog()
                 .penaltyDeath()
                 .build());
5 голосов
/ 17 декабря 2011

Я думаю, вы уже знаете об этом,

однопоточная модель может привести к низкой производительности в приложениях Android, которые не учитывают последствия. Поскольку все происходит в одном потоке, выполняющем длинные операции, например, доступ к сети или запросы к базе данных, в этом потоке будет блокироваться весь пользовательский интерфейс. Никакое событие не может быть отправлено , включая события рисования, пока выполняется длинная операция. * С точки зрения пользователя приложение выглядит зависшим *. Еще хуже, если поток пользовательского интерфейса блокируется на более чем несколько секунд (в настоящее время около 5 секунд), пользователю предоставляется печально известный диалог «приложение не отвечает» (ANR).

ANR возникает, когда в «главном» потоке выполняется какая-то длительная операция. Это поток цикла событий, и если он занят, Android не может обрабатывать какие-либо дальнейшие события GUI в приложении и, таким образом, выдает диалог ANR.

Что вызывает ANR?

В Android за отзывчивостью приложений следят системные службы Activity Manager и Window Manager. Android отобразит диалоговое окно ANR для определенного приложения, когда обнаружит одно из следующих условий:

* No response to an input event (e.g. key press, screen touch) within 5 seconds
* A BroadcastReceiver hasn't finished executing within 10 seconds

Как решить эту проблему, пожалуйста, посмотрите Проектирование для отзывчивости

EDIT:

Итак, попробуйте использовать другой отдельный рабочий поток, обработчик, AsyncTask или UIThread для вашей камеры (медиа-рекордер) вместо основного потока действия.

1). Сделайте "adb shell cat /data/anr/traces.txt", чтобы увидеть, чем занималось ваше приложение в таком случае. Это самый первый шаг, который вам нужно сделать: понять то, что делает ваше приложение, вызывает ANR.

Когда происходит ANR, все стеки процесса записываются в этот файл, с процессом, обвиняемым в ANR сначала. Все это делает это дамп файла, чтобы вы могли посмотреть на него. Так что вы просто хотите посмотреть на это немного время после ANR, прежде чем произойдет другой ANR.

2). Если ничто не кажется проблемой, используйте DDMS и включите представление потока. Это показывает все темы в вашем приложении похожи на след, который у вас есть. Воспроизведите ANR и обновить основной поток в то же время. Это должно показать вам точно, что происходит во время ANR.

Более того, просто пройдите этот http://android -developers.blogspot.com / 2009/05 / painless-threading.html

1 голос
/ 24 декабря 2011

Похоже, что ресурс камеры не освобождается, что вызывает ANR .

Код выглядит немного грязно. Вы можете взглянуть на пример API для камеры Предварительный просмотр:

Вам нужно будет внедрить onPause и onResume для надежной работы.

1 голос
/ 19 декабря 2011

Может быть, вы инициализируете и запускаете медиа-рекордер в самом основном потоке либо в Oncreate(), либо в Onresume(), вместо запуска камеры в основном потоке используйте separeate Handler, чтобы запустить камеру для фотографирования, это будет действовать как ребенок основного потока пользовательского интерфейса.

Используя Handler, вы сокращаете время, и ANR не возникает.

...