开发者

How to safely turn WebView zooming on and off as needed

开发者 https://www.devze.com 2023-02-16 07:24 出处:网络
As mentioned in this unanswered question: WebView throws Receiver not registered: android.widget.ZoomButtonsController

As mentioned in this unanswered question: WebView throws Receiver not registered: android.widget.ZoomButtonsController

By turning the WebView zoom controls on and off as needed throws this:

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

For some users. I myself have not seen this crash, but I have seen it in the logs coming from devices in the wild. It doesn't happen super frequently, but it is a crash regardless. Any ideas?

Thanks

Update: How to reproduce

I found how to reproduce this crash: http://code.google.com/p/android/issues/detail?id=15694

I'll report back if I discover a workaround.


As requested, the full stack trace:

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)

and another similar one:

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.hand开发者_如何学GoleMessage(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)


On a Zoom, I found that if one waits for the zoom control to fade out before calling WebView.destroy() a crash no longer occurs. So I've overwritten WebView.destroy() to post a message to a Handler to call WebView.destroy() after a few seconds. From the WebView source we will see the fade-out interval is:

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

So I used ViewConfiguration.getZoomControlsTimeout() + 1000L as the delay before calling WebView's destroy method. So far no crashes.


If you only want to have pinch zoom working with your webview and you can live without the zoom buttons, you can do this to your webview:

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

adding

webView.getSettings().setBuiltInZoomControls(true);

in onDestroy / onDestroyView did not help on 3.x.


webView.getSettings().setBuiltInZoomControls(true); did not work for me.

dkneller's suggestion did work, however:

    long timeout = ViewConfiguration.getZoomControlsTimeout();
    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
            webview.destroy();
        }
    }, timeout);


Put this line in onDestroy works for me:

webView.setVisibility(View.GONE);


This solution works fine, you simply need to remove the webview from the layout before destroying it:

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

No handlers, no delays, i think it's the best solution


If you are stumbling upon this question, be sure to check the bug report first to see what the status is from Google, but otherwise here is a workaround that is working so far so good for me:

Add this line to your onDestory() method:

webView.getSettings().setBuiltInZoomControls(true);


I have the same issue here: Existent app blowing up with android 3.0 XOOM. ZoomButtonsController Leak?

This happens when there's an exception that happens before registerReceiver is called and then you try to unregisterReceiver later without it ever been registered.

It's probably a android 3.0 bug.


java.lang.IllegalArgumentException: View not attached to window manager exception mostly occurs when there is a dialog (i.e. Progress Dialog) and you are dismissing it when the Activity has closed. Could you tell if your Activity indeed has a Progress Dialog in it , so that I can continue with my analysis ? Also post your Activity's code snippet which might help us identifying why your app is crashing ...

Also you say you don't face application crash often frequently, so do a test to confirm my suspicions. When your application is running change your screen orientation , and do it a couple of times , after few minutes, preferably when there is Progress Dialog involved in doing some work. It might crash the application which should tell us that the error is because the Progress Dialog isn't dismissing correctly.

My Theory : When you switch orientations, Android will create a new View. You're probably getting crashes because your background thread is trying to change the state on the old one. (It may also be having trouble because your background thread isn't on the UI thread)


Add this to your activity:

@Override
  public void finish() {
      ViewGroup view = (ViewGroup) getWindow().getDecorView();
      view.removeAllViews();
      super.finish();
}
0

精彩评论

暂无评论...
验证码 换一张
取 消