Как заставить медиаплеер останавливаться при нажатии кнопки возврата устройства из фрагмента обратно в активность

Моя проблема в том, что медиаплеер продолжает играть, когда я нажимаю кнопку возврата устройства. Как полностью уничтожить фрагмент и медиаплеер и все что в нем при нажатии на кнопку возврата устройства, чтобы его не было видно на экране?

Я новичок в программировании, поэтому приветствуются любые советы и комментарии по улучшению кода. Спасибо

Деятельность:

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button button1;
    Button button2;
    Button button3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        button1 = findViewById(R.id.button1);
        button2 = findViewById(R.id.button2);
        button3 = findViewById(R.id.button3);

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FragmentManager fm= getSupportFragmentManager();
                fragment1 fragment = new fragment1();
                fm.beginTransaction()
                        .replace(R.id.container,fragment)
                        .addToBackStack(null)
                        .commit();
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FragmentManager fm= getSupportFragmentManager();
                fragment2 fragment= new fragment2();
                fm.beginTransaction()
                        .replace(R.id.container,fragment)
                        .addToBackStack(null)
                        .commit();
            }
        });

        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FragmentManager fm= getSupportFragmentManager();
                fragment3 fragment= new fragment3();
                fm.beginTransaction()
                        .replace(R.id.container,fragment)
                        .addToBackStack(null)
                        .commit();
            }
        });
    }
}

Фрагмент:

import androidx.fragment.app.Fragment;
import android.media.MediaPlayer;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.Button;
import android.os.Bundle;
import android.widget.SeekBar;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;
import java.io.IOException;

public class fragment1 extends Fragment {

    MediaPlayer mp;
    Button play;
    SeekBar seekBar;
    TextView elapsedTimeLabel;
    TextView remainingTimeLabel;
    int totalTime;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_fragment1, container, false);

        final MediaPlayer mp = new MediaPlayer();
        try {
            mp.setDataSource("https://firebasestorage.googleapis.com...");
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            mp.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }

        final Button play = rootView.findViewById(R.id.play);
        elapsedTimeLabel = rootView.findViewById(R.id.elapsedTimeLabel);
        remainingTimeLabel = rootView.findViewById(R.id.remainingTimeLabel);
        totalTime = mp.getDuration();
        mp.seekTo(0);
        seekBar = rootView.findViewById(R.id.seekBar);
        seekBar.setMax(totalTime);
        seekBar.setOnSeekBarChangeListener

                (new SeekBar.OnSeekBarChangeListener() {
                     @Override
                     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                         if (fromUser) {
                             mp.seekTo(progress);
                             seekBar.setProgress(progress);
                         }
                     }
                     @Override
                     public void onStartTrackingTouch(SeekBar seekBar) {
                     }
                     @Override
                     public void onStopTrackingTouch(SeekBar seekBar) {
                     }
                 }
                );

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (mp != null) {
                    try {
                        Message msg = new Message();
                        msg.what = mp.getCurrentPosition();
                        handler.sendMessage(msg);
                        Thread.sleep(1000);
                    } catch (InterruptedException ignored) {
                    }
                }
            }
        }).start();

        mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

            public void onCompletion(MediaPlayer sound) {

                play.setBackgroundResource(R.drawable.play);
            }
        });

        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mp.isPlaying()) {
                    mp.pause();
                    play.setBackgroundResource(R.drawable.play);

                } else {

                    mp.start();
                    play.setBackgroundResource(R.drawable.pause);
                }

            }

        });

        return rootView;
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int currentPosition = msg.what;
            seekBar.setProgress(currentPosition);

            String elapsedTime = createTimeLabel(currentPosition);
            elapsedTimeLabel.setText(elapsedTime);

            String remainingTime;
            remainingTime = createTimeLabel(totalTime - currentPosition);
            remainingTimeLabel.setText("-" + remainingTime);
        }
    };

    public String createTimeLabel(int time) {
        String timelabel;
        int min = time / 1000 / 60;
        int sec = time / 1000 % 60;

        timelabel = min + ":";
        if (sec < 10) timelabel += "0";
        timelabel += sec;
        return timelabel;

    }


    public void play(View view) {
        if (mp == null) {
            mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    stopPlayer();
                }
            });
        }

        mp.start();
    }

    public void pause(View view) {
        if (mp != null) {
            mp.pause();
        }
    }

    private void stopPlayer() {
        if (mp != null) {
            mp.release();
            mp = null;

        }
    }
}

ИЗМЕНИТЬ:

Я пробовал предоставленные решения, но почему-то медиаплеер во фрагменте не уничтожается. Когда я возвращаюсь к фрагменту, панель поиска в нем сбрасывается, но аудиофайл все еще воспроизводится. Когда я снова нажимаю кнопку воспроизведения, он снова начинает воспроизводиться поверх предыдущего, так что одновременно воспроизводятся 2 файла.


person sks    schedule 05.10.2020    source источник


Ответы (3)


Каждый фрагмент имеет обратный вызов onDestroy(), когда фрагмент извлекается из заднего стека и уничтожается. Вы можете вызвать свой stopPlayer() из этого метода.

@Override
public void onDestroy() {
    super.onDestroy();
    stopPlayer();
}
person ianhanniballake    schedule 05.10.2020
comment
Что не сработало? Если вы на самом деле извлекаете свой фрагмент из заднего стека, то будет вызываться onDestroy(). Вызывается ли onDestroy(), когда вы впервые переходите к своему фрагменту, а затем нажимаете системную кнопку «Назад»? - person ianhanniballake; 05.10.2020
comment
СМИ все еще продолжали играть, когда я нажал назад. Извините, я не могу быть более конкретным. Я вставил ваш ответ во фрагмент, но медиа все еще продолжало играть. Я дал весь код в своем первоначальном вопросе. Спасибо, что ответили в любом случае - person sks; 05.10.2020

К сожалению, нет прямого способа сделать это. Поскольку у фрагмента нет метода onBackPressed(), вам придется сделать обратный вызов и реализовать его во фрагменте, чтобы он заработал.

Во-первых, вам нужно создать интерфейс и класс, который реализует свой интерфейс, чтобы иметь общий метод.

  1. Создать интерфейс класса OnBackPressedListener

OnBackPressedListener.java

public interface OnBackPressedListener {
    void goBack();
}
  1. в вашем MainActivity Создайте прослушиватель и создайте для него установщик и используйте его внутри метода onBackPressed() после его переопределения.

Ваш MainActivity должен быть примерно таким

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private OnBackPressedListener onBackPressedListener;

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null){
            onBackPressedListener.goBack();
        }
        super.onBackPressed();
    }
}
  1. В интерфейсе Fragment you should implement the OnBackPressedListener` и используйте его для остановки проигрывателя

Фрагмент1.java

public class fragment1 extends Fragment implements OnBackPressedListener {
    
    @Override
    public void goBack() {
        stopPlayer();
    }
}

Примечание

  • Подумайте о том, чтобы преобразовать ваше имя fragment1 в Fragment1 с заглавными буквами F.
person Hamza Sharuf    schedule 05.10.2020
comment
Вы также должны удалить слушателя, чтобы избежать утечек памяти. Создайте новую функцию в MainActivity, назовите ее removeOnBackPressedListener и установите для слушателя значение null. и когда вы вернетесь из Fragment, вы должны позвонить ему - person Hamza Sharuf; 05.10.2020
comment
Обратите внимание, что это уже не так: любой компонент, включая фрагмент, может зарегистрировать OnBackPressedCallback в соответствии с документацию и перехватить дескриптор кнопки «Назад». - person ianhanniballake; 05.10.2020
comment
Хамза Шаруф и ianhanniballake, я попробовал оба ваших решения, и СМИ все еще продолжали играть, когда я нажал - person sks; 05.10.2020
comment
мой плохой, я думал, что это только для компонента навигации реактивного ранца. В любом случае. @sks Мое решение делает именно то, что делает другое решение. И лучше следовать решению Яна и просто игнорировать этот обходной путь. - person Hamza Sharuf; 05.10.2020

@Override
public void onDestroy() {
    stopPlayer();
    super.onDestroy();
}

Во Фрагменте переопределите функцию OnDestroy. и остановить проигрыватель перед вызовом super.onDestroy()

person Zeeshan Ayaz    schedule 05.10.2020
comment
Какой медиаплеер вы используете? - person Zeeshan Ayaz; 05.10.2020
comment
по умолчанию? Класс MediaPlayer - person sks; 05.10.2020