阿里云首页 移动测试

java_lang_IllegalArgumentException

问题分析

根据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()之后没有释放锁资源,正确的流程是:

  1. 调用mSurfaceHolder.lockCanvas(); 获取Canvas对象。

  2. 调用Canvas方法进行绘图:canvas.drawXXX(arg, arg, arg, arg);

  3. 绘图完成之后,调用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;
  }

参考文章