问题分析
根据Android官方文档,当方法接收到了一个不合法或不正确的参数时会抛出此类异常。
解决方案
因为参数不合法导致抛出IllegalArgumentException,请根据堆栈信息描述的出错的函数参数,按照要求传入正确的参数。
代码示例
public static void getUserAgent(Context context) {
WebView webview = new WebView(context);
WebSettings settings = webview.getSettings();
userAgent = settings.getUserAgentString();
Log.i("UserAgent:" + userAgent);
}
示例一
java.lang.IllegalArgumentException: HTTP parameters may not be null
at org.apache.http.params.HttpProtocolParams.getUserAgent(HttpProtocolParams.java:150)
at org.apache.http.impl.client.AbstractHttpClient.isMoMMS(AbstractHttpClient.java:790)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:563)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:520)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:498)
at com.g.utils.HttpClientUtil.post(HttpClientUtil.java:99)
at com.g.utils.LoadDataFromServer$2.run(LoadDataFromServer.java:195)
因为参数为空导致获取字符集失败抛出的异常。
在该示例中,getUserAgent因为userAgent变量为空,所以报错。User Agent中文名为用户代理,简称UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
示例二
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:243)
at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2435)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2409)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2253)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1883)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:544)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
该问题在Android诸多系统版本均有出现。这个问题是由于Android系统的bug导致Webview内存无法被正确管理,从而导致内存泄漏。当内存太低时,绘图时无法申请到内存资源,导致此异常抛出,应用崩溃。
解决方法如下:
1:强制管理Webview的生命周期。在Webview对应的Activity的声明周期管理中,对webview进行强制的管理。当Activity在onPause()
时,强制destory掉webview,并清空webview的container。这样,webview占用的内存会在下一次GC时,被系统回收。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
View v = super.onCreateView(inflater, container, saved);
mActivity = (BaseActivity) getSupportActivity();
// this is the framelayout which will contain our WebView
mWebContainer = (FrameLayout) v.findViewById(R.id.web_container);
return v;
}
public void onResume() {
super.onResume();
// create new WebView and set all its options.
mWebView = new WebView(mActivity);
mWebView....
// add it to the container
mWebContainer.addView(mWebView);
// if data is available, display it immediately
if(mTopic != null) {
mWebView.loadDataWithBaseURL("file:///android_asset/", mTopic.getHtmlCache(),
"text/html", "UTF-8", null);
}
}
@Override
public void onPause() {
super.onPause();
// destroy the webview
mWebView.destroy();
mWebView = null;
// remove the view from the container.
mWebContainer.removeAllViews();
}
2:取消应用的硬件加速
在AndroidManifest.xml
里增加android:hardwareAccelerated="false"
,用来禁止硬件加速,此方法可以避免该系统bug。不过,不推荐游戏或者对流畅性要求很高的应用采用此方法,可能会导致应用变得有一些卡顿。
示例三
01-17 00:19:44.703: E/Surface(9731): Surface::lock failed, already locked
01-17 00:19:44.796: E/SurfaceHolder(9731): Exception locking surface
01-17 00:19:44.796: E/SurfaceHolder(9731): java.lang.IllegalArgumentException
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.Surface.lockCanvasNative(Native Method)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.Surface.lockCanvas(Surface.java:314)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.SurfaceView$3.internalLockCanvas(SurfaceView.java:762)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.SurfaceView$3.lockCanvas(SurfaceView.java:741)
01-17 00:19:44.796: E/SurfaceHolder(9731): at com.frequency.FreqTapArea$2.onTouch(FreqTapArea.java:54)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.View.dispatchTouchEvent(View.java:3897)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
01-17 00:19:44.796: E/SurfaceHolder(9731): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1737)
01-17 00:19:44.796: E/SurfaceHolder(9731): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1153)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
01-17 00:19:44.796: E/SurfaceHolder(9731): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1721)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2200)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.view.ViewRoot.handleMessage(ViewRoot.java:1884)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.os.Handler.dispatchMessage(Handler.java:99)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.os.Looper.loop(Looper.java:130)
01-17 00:19:44.796: E/SurfaceHolder(9731): at android.app.ActivityThread.main(ActivityThread.java:3835)
01-17 00:19:44.796: E/SurfaceHolder(9731): at java.lang.reflect.Method.invokeNative(Native Method)
01-17 00:19:44.796: E/SurfaceHolder(9731): at java.lang.reflect.Method.invoke(Method.java:507)
01-17 00:19:44.796: E/SurfaceHolder(9731): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
01-17 00:19:44.796: E/SurfaceHolder(9731): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
01-17 00:19:44.796: E/SurfaceHolder(9731): at dalvik.system.NativeStart.main(Native Method))
Canvas在操作之前需要加锁(lockCanvas函数),操作结束后,应该立即释放锁资源(unlockCanvasAndPost函数),这个问题的出现就是因为lockCanvas()
之后没有释放锁资源,正确的流程是:
调用
mSurfaceHolder.lockCanvas();
获取Canvas对象。调用Canvas方法进行绘图:
canvas.drawXXX(arg, arg, arg, arg);
绘图完成之后,调用
mSurfaceHolder.unlockCanvasAndPost(c);
释放锁资源。
public boolean draw(View arg0, MotionEvent arg1) {
Canvas c = mSurfaceHolder.lockCanvas();
// Draw something
c.drawCircle(args,…,arg);
mSurfaceHolder.unlockCanvasAndPost(c);
return true;
}