Используя «это» в качестве контекста в блоке действий init? - PullRequest
0 голосов
/ 26 января 2020

Я занимаюсь разработкой приложения android с kotlin.

У меня есть класс DereDatabaseHelper с блоком init, который использует context, заданный параметром класса (? )

DereDatabaseHelper похож на это.

class DereDatabaseHelper(context: Context) {
    val manifestFile: File
    val fumensDBFile: File
    val fumenFolder: File

    val musicIDToInfo: MutableMap<Int, MusicInfo> = HashMap()
    val fumenIDToMusicID: SparseIntArray = SparseIntArray()

    init {
        val datadir = context.getExternalFilesDir(null).parentFile.parentFile

Класс DereDatabaseHelper здесь описан в SongListActivity вот так.

class SongListActivity : AppCompatActivity() {
    var dereDatabaseHelper : DereDatabaseHelper
    init {
        dereDatabaseHelper = DereDatabaseHelper(this)
    }

Я думал, что этот код правильный, но этот код выдает NullPointerException.

java .lang.NullPointerException: Попытка вызвать виртуальный метод

'java. io.File android .content.Context.getExternalFilesDir (java .lang.String) '

для пустой ссылки на объект в

android .content.ContextWrapper.getExternalFilesDir ( ContextWrapper. java: 253) в com.kyhsgeekcode.dereinfo.model.DereDatabaseHelper. (DereDatabaseHelper.kt: 21) в com.kyhsgeekcode.dereinfo.SongListActivity. (SongListActivity.kt: 31)

Является ли this нулевым, когда выполнение находится в блоке init, и какой стиль инициализации мне следует использовать, чтобы это исправить?

Ответы [ 2 ]

1 голос
/ 26 января 2020

Никогда не используйте конструктор Activity для выполнения чего-либо, что включает в себя Context. Android создает действия с использованием своего единственного пустого конструктора (через отражение), а затем устанавливает различные поля действия до , когда оно вызывает onCreate(). Ваша первая безопасная точка входа для выполнения каких-либо действий в вашей Активности находится в onCreate().

Вы также не можете вызывать методы Активности (которая сама является Контекстом) в конструкторе.

Вы также не можете использовать контекст каким-либо образом даже для настройки свойств, потому что они попытаются получить доступ к контексту до onCreate:

class MyActivity: AppCompatActivity() {
    val assets: AssetManager = getAssets() // This will cause a crash
}

Чтобы избежать необходимости обнулять ваше свойство, вы может выполнить одно из следующих действий, что позволит вам избежать создания экземпляра вашего класса до тех пор, пока не будет вызван onCreate():

class SongListActivity : AppCompatActivity() {
    lateinit var dereDatabaseHelper : DereDatabaseHelper

    override fun onCreate() {
        super.onCreate
        dereDatabaseHelper = DereDatabaseHelper(this)
    }

или

class SongListActivity : AppCompatActivity() {
    val dereDatabaseHelper by lazy { DereDatabaseHelper(this) }
}
1 голос
/ 26 января 2020

Действия не полностью инициализируются блоком constructor или, в вашем случае, init.

Android система инициализирует действия и затем вызывает метод onCreate. Поэтому вы должны сделать следующее

override fun onCreate(savedInstanceState: Bundle?) {
 // create instance of DareDatabaseHelper 
}

Почему это не работает с конструктором?

рассмотрите следующий фрагмент кода

var myActivity = MyActivity() // This doesn't start MainActivity

// This is how you start an activity
val intent = Intent(context, MyActivity::class.java)
startActivity(intent)

Когда вы запускаете какое-либо действие, вы никогда не создаете экземпляр класса действия, почему?

Потому что это ответственность android системы, когда вы делаете startActivity(intent) android система создает экземпляр вашего activity класса, используя значение по умолчанию constructor, а затем выполняет всю инициализацию (ie. Предоставляя context). И как только activity полностью инициализируется, onCreate метод вашей активности называется, где вы можете сделать ваш конец инициализации.

...