In Android app development, webview is widely used. However, if you are using webview without caution, it will easily consume a lot of memory. And your app may even crash due to insufficient memory.
The memory issue of webview is well-known, here are two great links about the issue.
For Android 4.4 and above, Android is using chromium as the core of webview. For Android 3.1 to 4.3, Android is using webkit as the core of webview. Most of the memory leak happens on webkit.
And the blog will briefly summarize the tips to prevent webview memory leak
Tip 1: When clearing the webview reference. Simply set it to null is not enough.webview.destroy()must be called. Example code:
123456789
@OverridepublicvoidonDestroy(){super.onDestroy();if(webView!=null){webView.removeAllViews();webView.destroy();}webView=null;}
Tip 2: Using application context when initializing webview. This means webview should not be initialized from xml. You need to create it programmatically. Example Code:
123
WebViewwebView=newWebView(getApplicationgContext());LinearLayoutlinearLayout=findViewById(R.id.xxx);linearLayout.addView(webView);
By doing this, 90% of the time, webview memory consumption is no longer an issue. However, if you want to play a full screen video in your webview, theonShowCustomerViewofWebChromeClientwill be triggered. And beforeonShowCustomerViewis triggered, the Webkit will do some preprocessing. Due to a bug in Webkit’s implementation, a static variable inhtml5videoviewproxywill hold the webview’s reference which will caused a leak and you cannot do much about it.
Another problem using application context is that when your webview wants to popup a window. In webview’s default behaviour, there is a cast fromApplicationContexttoActivityContextwhich will cause your app crash. Of course, you can implement your own method of handling popup to walk around this problem, but it takes a lot of unnecessary effort.
P.S. we can inject javascript into webview to do many tricks. I will later post another blog about using javascript in webview.
Tip 3: I personally did not test this method, but I think the method is creative and instructive so I am noticing it down here.
The main idea is webkit does not provide us a method to release the reference, so let us do it ourself by reflection. The reason why I did not use it is because it highly depends on webkit’s implementation and you have to write different code for different Android versions.
123456789101112131415161718
publicvoidsetConfigCallback(WindowManagerwindowManager){try{Fieldfield=WebView.class.getDeclaredField("mWebViewCore");field=field.getType().getDeclaredField("mBrowserFrame");field=field.getType().getDeclaredField("sConfigCallback");field.setAccessible(true);ObjectconfigCallback=field.get(null);if(null==configCallback){return;}field=field.getType().getDeclaredField("mWindowManager");field.setAccessible(true);field.set(configCallback,windowManager);}catch(Exceptione){}}
Call the method in onCreate and onDestroy
123456789
publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setConfigCallback((WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE));}publicvoidonDestroy(){setConfigCallback(null);super.onDestroy();}
Ultimate Tip: This method is the ultimate way to solve the problem and many well-known app such as QQ and Wechat are using it as well.
The idea is to start a separate process for webview and kill the process when existing the webview. The drawback of doing this is that you need to handle interprocess communication carefully. My suggestion is you can create apreProcessProxyandpostProcessProxyto handle IPC and passing information around using intent.
Example code: define webview activity in a separate process
12345
Kill the process when destroying the activity