[Kotlin] 継承したUI要素をXMLレイアウトで利用する際のInflateException

By | 2018年1月10日

AndroidアプリのレイアウトをXMLファイル(activity_main.xml)で設定している場合、あるウィジェットやレイアウトなどのUI要素を継承した「拡張UI要素」を配置しようとして以下のエラーが発生することがあります。

android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class [クラス名]

これは、継承して作ったUI要素のクラスに書くべきコンストラクタが足りていないことが原因となります。実際のプログラムを例に原因と解決方法を紹介します。

InflateExceptionが起こるプログラム

以下のような Kotlin のプログラムとレイアウト用XMLでアプリが作られているとします。

MainActivity.kt

package com.example.test.testproject

import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

class MyView(context: Context?) : View(context) {

    init {
        Log.i("debug", "継承して作ったView")
    }
}

クラス MyView が View を継承して作った拡張UI要素です。第1コンストラクタ(プライマリコンストラクタ)のみを定義しています。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.test.testproject.MainActivity">

    <com.example.test.testproject.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

拡張したUI要素(com.example.test.testproject.MyView)を配置しています。

プログラムで定義したUI要素をXMLファイルで配置する場合は、パッケージ名も含めたフルネームで記述します。

以上のファイルからなるアプリを実行してみると「InflateException」が発生し、アプリが強制終了します。

この原因は MainActivity.kt の MyView にコンストラクタの定義が足りないことです。プライマリコンストラクタ(第一コンストラクタ)だけでなく、あと2つコンストラクタを定義する必要があります。

XMLレイアウトから継承したUI要素を利用するために必要なコンストラクタ

この3つのコンストラクタを継承したクラスに定義します。

修正されたプログラム

MainActivity.kt の MyView を以下のように修正します。

...(略)...

class MyView : View {

    constructor(context: Context): super(context) {
        Log.i("debug", "継承して作ったView コンストラクタ1")
    }

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        Log.i("debug", "継承して作ったView コンストラクタ2")
    }

    constructor(context: Context, attributeSet: AttributeSet, defStyle: Int) : super(context, attributeSet, defStyle) {
        Log.i("debug", "継承して作ったView コンストラクタ3")
    }
}

XMLレイアウトの修正は必要ありません。

修正後、プログラムを実行してみると問題なく動作し、コンソールには第2コンストラクタが呼ばれたことが確認できるログが表示されます。

第2コンストラクタが呼ばれたことを表すログ

おしまい

上記の例ではプログラムの言語が Kotlin でしたが、言語が Java の場合でも原因と解決方法は同じです。

また、今回は親となるUI要素が View でしたが、ラベル(TextView)やテキストエリア(EditText)のような別のUI要素でも同様です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です