Android (Kotlin) - Невозможно получить доступ к представлению из другого класса - PullRequest
1 голос
/ 13 июля 2020

У меня есть класс деятельности под названием MusicPlayer и внешний класс под названием MpPlayer. В последнем случае моя цель - изменить раскладку MusicPlayer. Однако, даже если я передаю контекст из MusicPlayer в MpPlayer, приложение продолжает возвращать исключение java .lang.NullPointerException всякий раз, когда класс MpPlayer пытается получить доступ к макету.

Я немного очистил код, чтобы легко было прочитать проблему;

Мой основной класс с представлением:

 open class MusicPlayer : AppCompatActivity() {

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

            mp = MpPlayer(this@MusicPlayer)
            mp.loadMusic //error here
    }
}

И мой второй класс:

class MpPlayer(private var playerReference: MusicPlayer){

    init{
        playerReference = MusicPlayer()
    }

    fun loadMusic(url: String){
            musicPlayer.apply {
                reset()
                setDataSource(url)
                prepareAsync()
                setOnPreparedListener { mp ->
                    totaltime = mp.duration
                    playerReference.seekBar.max = totaltime         //error here
                    playerReference.txt_musicName.text = playerReference.musicNameList[musicCounter]
                    playerReference.txt_musicArtist.text = playerReference.musicArtistList[musicCounter]
                    playerReference.btn_musicplayPause.setImageResource(R.drawable.ic_play)

                    if (wanting2Play) {
                        mp.start()
                        playerReference.btn_musicplayPause.setImageResource(R.drawable.ic_pause)
                    }

                }
                setOnCompletionListener { skipNext() }
            }
        }
}

Logcat:

2020-07-13 17:27:11.278 21742-21742/com.android.slowfy E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.slowfy, PID: 21742
    java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
        at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:159)
        at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:157)
        at android.content.Context.obtainStyledAttributes(Context.java:675)
        at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:692)
        at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:659)
        at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:479)
        at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:214)
        at com.android.slowfy.MpPlayer$loadMusic$$inlined$apply$lambda$1.onPrepared(MpPlayer.kt:41)
        at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:3367)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2020-07-13 17:32:11.329 21742-21775/com.android.slowfy E/Surface: queueBuffer: error queuing buffer to SurfaceTexture, -19
2020-07-13 17:32:11.330 21742-21775/com.android.slowfy E/EGL_emulation: tid 21775: swapBuffers(570): error 0x300d (EGL_BAD_SURFACE)

Мы будем благодарны за любые мысли по этому поводу :)

1 Ответ

3 голосов
/ 13 июля 2020

Здесь, в вашем блоке init, вы заменили переданное в Activity новым экземпляром:

class MpPlayer(private var playerReference: MusicPlayer){

    init{
        playerReference = MusicPlayer()
    }

Сначала удалите этот блок init. Обратите внимание, что действия никогда не должны создаваться напрямую, потому что тогда они не будут настроены должным образом, чтобы иметь возможность использовать свой контекст. Кроме того, вам нужно разрешить Activity удалять себя в качестве слушателя при закрытии, поэтому сделайте свойство обнуляемым и установите для него значение null при уничтожении Activity. В противном случае ваш класс MPPlayer может попытаться обновить представления, когда Activity уже ушел, и он также будет пропускать Activity.

class MpPlayer(var playerReference: MusicPlayer?){
open class MusicPlayer : AppCompatActivity() {
    //...
    override fun onDestroy() {
        super.onDestroy()
        mp.playerReference = null
    }
}

Я также отмечу, что передача Activity в musi c проигрыватель плохо использует инкапсуляцию. Вы тесно связываете эти два класса, как спагетти, когда игрок musi c должен иметь возможность работать независимо, не зная классов View. Я рекомендую создать класс прослушивателя для различных событий MusicPlayer и реализовать их в Activity, например:

class MpPlayer(var eventListener: EventListener?){

    interface EventListener {
        fun onPlayerPrepared(mediaPlayer: MediaPlayer)
        fun onPlaybackCompleted(mediaPlayer: MediaPlayer)
        //etc. anything views in Activity might want to respond to
    }

    fun loadMusic(url: String){
            musicPlayer.apply {
                reset()
                setDataSource(url)
                prepareAsync()
                setOnPreparedListener { mp ->
                    eventListener?.onPlayerPrepared(mp)
                }
                setOnCompletionListener { 
                    eventListener?.onPlaybackCompleted(mp)
                    skipNext() 
                }
            }
        }
}

Я также рекомендую поставить слово «Activity» в имени любого класса Activity, чтобы избежать путаницы.

class MusicPlayerActivity : AppCompatActivity(), MpPlayer.EventListener {

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

            mp = MpPlayer(this)
            mp.loadMusic()
    }

    override fun onPlayerPrepared(mediaPlayer: MediaPlayer){
        totaltime = mp.duration
        seekBar.max = totaltime
        txt_musicName.text = playerReference.musicNameList[musicCounter]
        txt_musicArtist.text = playerReference.musicArtistList[musicCounter]
        btn_musicplayPause.setImageResource(R.drawable.ic_play)
        //...
    }

    override fun onPlaybackCompleted(mediaPlayer: MediaPlayer) {
        //...
    }

    override fun onDestroy() {
        super.onDestroy()
        mp.eventListener = null
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...