AndroidのカスタムView内で使用していたCanvas#clipPath()
でUnsupportedOperationException
が発生したので調査していたところ、原因が「Hardware acceleration」という聞きなれない機能でした。
同じようにハマる人がいそうなので、「Hardware acceleration」の概要と制御の仕方をメモしておきます。
カスタムViewを作る人は知っておいたほうがいいです。
概要
ハードウェアアクセラレーションはViewの描画処理にGPUを使用することで効率化する機能です。
以下、注意点。
- Hardware acceleration はAPIレベル14以上でデフォルトON
- 標準のViewとDrawableを使う分には常にONで影響なし
- 全ての描画処理をサポートしているわけではないので、ONになっているとカスタムViewで問題がでる場合がある
- 意図しない描画になったり、最悪例外が発生してクラッシュします。今回は
Canvas#clipPath()
がAPIレベル18以上でないとサポートされていなかったので例外発生しました。 - 各メソッドのサポート状況で自分が使っているメソッドをサポートしているAPIレベルを確認しておくことをオススメします
- 意図しない描画になったり、最悪例外が発生してクラッシュします。今回は
設定方法
以下のレベルでハードウェアアクセラレーションの制御が可能です。
(具体的な制御方法は最後の参考リンクの公式ドキュメントを参照してください)
- Application => AndroidManifest.xmlで設定
- Activity => AndroidManifest.xmlで設定
- Window => コードで設定
- View => コードで設定、ただし現在OFFにすることだけ可能
使いたいメソッドをサポートしているAPIレベルを確認して、満たしていないときはOFFにする、という対応が一番簡単だと思います。
今回は、以下のようにカスタムViewの例のように、サポートしていないAPIレベルの場合は、ビューレベルでOFFにすると意図した描画になりました。
@Override
protected void onDraw(Canvas canvas) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
// Turn off hardware acceleration to use Canvas#clipPath()
// See https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
canvas.clipPath(mPath);
super.onDraw(canvas);
}