Как безопасно включать и выключать масштабирование WebView по мере необходимости

Как уже упоминалось в этом вопросе без ответа: WebView выдает Receiver не зарегистрирован: android.widget .ZoomButtonsController

Включение и выключение элементов управления масштабированием WebView по мере необходимости приводит к следующему:

java.lang.IllegalArgumentException: Receiver not registered: android.widget.ZoomButtonsController

Для некоторых пользователей. Я сам не видел этого сбоя, но видел его в логах, поступающих с устройств в дикой природе. Это случается не очень часто, но, тем не менее, это сбой. Любые идеи?

Спасибо

Обновление: как воспроизвести

Я нашел, как воспроизвести этот сбой: http://code.google.com/p/android/issues/detail?id=15694

Я сообщу, если найду обходной путь.


По запросу полная трассировка стека:

java.lang.IllegalArgumentException: Receiver not registered: android.widget.ZoomButtonsController$1@487a4290
at android.app.ActivityThread$PackageInfo.forgetReceiverDispatcher(ActivityThread.java:793)
at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:913)
at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:331)
at android.widget.ZoomButtonsController.setVisible(ZoomButtonsController.java:404)
at android.widget.ZoomButtonsController$2.handleMessage(ZoomButtonsController.java:178)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)

и еще один подобный:

java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:391)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:236)
at android.view.Window$LocalWindowManager.removeView(Window.java:432)
at android.widget.ZoomButtonsController.setVisible(ZoomButtonsController.java:406)
at android.widget.ZoomButtonsController$2.handleMessage(ZoomButtonsController.java:178)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:5068)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)

person cottonBallPaws    schedule 11.03.2011    source источник
comment
Можно мне полный краш-стек @littleFluffyKitty?   -  person Reno    schedule 17.03.2011
comment
@ Рено, привет! Вы уверены, что можете это сделать!   -  person cottonBallPaws    schedule 17.03.2011
comment
@the100rabh, прямо сейчас я просто включаю и выключаю его, устанавливая для getSettings().setBuiltInZoomControls() значение true или false, когда это необходимо. Тем не менее, в дикой природе он, похоже, вызывает сбои, описанные выше (не очень часто, но достаточно часто, чтобы найти другой метод).   -  person cottonBallPaws    schedule 19.03.2011


Ответы (9)


В Zoom я обнаружил, что если дождаться исчезновения элемента управления масштабированием перед вызовом WebView.destroy(), сбой больше не происходит. Поэтому я перезаписал WebView.destroy(), чтобы отправить сообщение обработчику для вызова WebView.destroy() через несколько секунд. Из источника WebView мы увидим, что интервал затухания:

// The time that the Zoom Controls are visible before fading away
private static final long ZOOM_CONTROLS_TIMEOUT =
        ViewConfiguration.getZoomControlsTimeout();

Поэтому я использовал ViewConfiguration.getZoomControlsTimeout() + 1000L в качестве задержки перед вызовом метода уничтожения WebView. Пока без сбоев.

person dkneller    schedule 11.05.2011

Если вы хотите, чтобы масштабирование работало только с вашим веб-просмотром, и вы можете жить без кнопок масштабирования, вы можете сделать это для своего веб-просмотра:

webView.getSettings().setBuiltInZoomControls(true); // will give pinch zoom
webView.getSettings().setDisplayZoomControls(false); // but won't display the zoom buttons

добавление

webView.getSettings().setBuiltInZoomControls(true);

в onDestroy/onDestroyView на 3.x не помогло.

person Stephan    schedule 30.07.2011

webView.getSettings().setBuiltInZoomControls(true); не работал для меня.

Однако предложение dkneller сработало:

    long timeout = ViewConfiguration.getZoomControlsTimeout();
    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
            webview.destroy();
        }
    }, timeout);
person dvn    schedule 06.03.2012
comment
У меня произошел сбой на некоторых устройствах (все сообщения 4.X 5.X 6.X) с приведенным выше ответом, java.lang.Throwable: метод WebView был вызван в потоке «Timer-0». Все методы WebView должны вызываться в одном потоке. (Ожидаемый Looper Looper (main, tid 1) {4240c348} вызывается при нулевом значении, к сведению, основным Looper является Looper (main, tid 1) - person droida; 04.11.2016

Поместите эту строку в onDestroy, которая работает для меня:

webView.setVisibility(View.GONE);

person Allen Chan    schedule 26.04.2012

Это решение отлично работает, вам просто нужно удалить веб-просмотр из макета перед его уничтожением:

@Override
    public void onDestroy() {
        if (webView!=null && webView.getParent()!=null){
            ((ViewGroup)webView.getParent()).removeView(webView);
            webView.destroy();
            webView=null;
        }
        super.onDestroy();
    }

Никаких обработчиков, никаких задержек, думаю это лучшее решение

person NullPointerException    schedule 09.12.2015

Если вы наткнулись на этот вопрос, обязательно сначала проверьте отчет об ошибке, чтобы узнать, какой статус от Google, но в остальном вот обходной путь, который до сих пор работает так хорошо для меня:

Добавьте эту строку в свой метод onDestory():

webView.getSettings().setBuiltInZoomControls(true);
person cottonBallPaws    schedule 23.03.2011
comment
Это исправление не решает проблему полностью. Попробуйте метод дкнеллера. - person cottonBallPaws; 14.07.2012

У меня такая же проблема: Существующее приложение выдувается с Android 3.0 XOOM. Утечка контроллера ZoomButtons?

Это происходит, когда есть исключение, которое происходит до вызова registerReceiver, а затем вы пытаетесь отменить регистрациюReceiver позже, когда он еще не был зарегистрирован.

Вероятно, это баг андроида 3.0.

person Rafael Sanches    schedule 19.03.2011
comment
Глядя на журналы ошибок, я видел, что это происходит и для устройств до версии 3.0. - person cottonBallPaws; 20.03.2011
comment
В соответствии с этим это может быть исправлено в сотах o_O - person Reno; 21.03.2011

Исключение java.lang.IllegalArgumentException: представление не привязано к диспетчеру окон в основном возникает, когда есть диалоговое окно (например, диалоговое окно прогресса), и вы закрываете его, когда действие закрыто. Не могли бы вы сказать, действительно ли в вашей деятельности есть диалоговое окно прогресса, чтобы я мог продолжить свой анализ? Также опубликуйте фрагмент кода своей активности, который может помочь нам определить, почему ваше приложение дает сбой...

Также вы говорите, что не часто сталкиваетесь со сбоем приложения, поэтому сделайте тест, чтобы подтвердить мои подозрения. Когда ваше приложение работает, измените ориентацию экрана и сделайте это пару раз, через несколько минут, желательно, когда диалоговое окно прогресса участвует в выполнении какой-либо работы. Это может привести к сбою приложения, которое должно сообщить нам, что ошибка связана с тем, что диалоговое окно «Прогресс» не закрывается правильно.

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

person Muhammad Shahab    schedule 19.03.2011
comment
Я думаю, вы объясняете об исключении WindowBadToken. Но здесь другой случай. - person Tofeeq Ahmad; 07.02.2013

Добавьте это в свою деятельность:

@Override
  public void finish() {
      ViewGroup view = (ViewGroup) getWindow().getDecorView();
      view.removeAllViews();
      super.finish();
}
person Biswajit Karmakar    schedule 14.05.2016