androidandroid-studiokotlinandroid-music-player

How to stop music from playing when user switch to other page in Android Studio Kotlin?


I have created a meditation application that users can select the class they want from the recycler view within the fragment, then it will show the detailed content and steps in a new activity. In the new activity, I have implemented a audio playing functions where user can stream the audio file from the firebase. The problem now is whenever I switch back to the recycler view within the fragment, the audio file still plays in the background. How do I stop the audio file from playing whenever I switch to another page within the app or switch to another app ?

This is the code for the recycler view within the fragment

class ClassFragment : Fragment() {

private lateinit var recyclerView: RecyclerView
private lateinit var classArrayList: ArrayList<Classes>
private lateinit var tempArraylist: ArrayList<Classes>
private lateinit var classAdapter: ClassAdapter
private lateinit var db: FirebaseFirestore
var mediaPlayer: MediaPlayer? = null

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val view: View = inflater.inflate(R.layout.fragment_class, container, false)
    recyclerView = view.findViewById(R.id.ClassList)
    recyclerView.layoutManager = LinearLayoutManager(context)
    recyclerView.setHasFixedSize(true)

    classArrayList = arrayListOf()
    tempArraylist = arrayListOf()
    eventChangeListener()
    classAdapter = ClassAdapter(requireContext(), classArrayList)

    recyclerView.adapter = classAdapter

    return view
}


private fun eventChangeListener() {
    db = FirebaseFirestore.getInstance()
    db.collection("class").addSnapshotListener(object : EventListener<QuerySnapshot> {
        override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
            if (error != null) {
                Log.e("Firestore error", error.message.toString())
                return
            }
            for (dc: DocumentChange in value?.documentChanges!!) {
                if (dc.type == DocumentChange.Type.ADDED) {

                    classArrayList.add(
                        dc.document.toObject(
                            (Classes::class.java)
                        )
                    )
                }
            }
            tempArraylist.clear()
            tempArraylist.addAll(classArrayList)
            classAdapter.notifyDataSetChanged()
        }
    })
}

}

This is the code for the new activity page where it will show content when the user selects from recyclerview

class DetailActivity : AppCompatActivity() {

private lateinit var imageViewClass: ImageView
private lateinit var textViewClassName: TextView
private lateinit var textViewClassDes: TextView
private lateinit var textViewClassContent: TextView
private var stop:Boolean = false
var mediaPlayer: MediaPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail)
    val btnPlay: Button = findViewById(R.id.btnPlay)
    val btnStop: Button = findViewById(R.id.btnStop)


    imageViewClass = findViewById(R.id.imageViewClassImage)
    textViewClassName = findViewById(R.id.textViewClassName)
    textViewClassDes = findViewById(R.id.textViewClassDescription)
    textViewClassContent = findViewById(R.id.textViewClassContent)


    val classImage = intent.getStringExtra("class_image")
    val className = intent.getStringExtra("class_name")
    val classDes = intent.getStringExtra("class_des")
    val classContent = intent.getStringExtra("class_content")
    val classAudio = intent.getStringExtra("class_audio")

    Glide.with(this)
        .load(classImage)
        .centerCrop()
        .into(imageViewClass)
    textViewClassName.text = className
    textViewClassDes.text = classDes
    textViewClassDes.text = classDes!!.replace("\\n", "\n")
    textViewClassContent.text = classContent
    textViewClassContent.text = classContent!!.replace("\\n", "\n")

    btnPlay.isEnabled = true
    btnStop.isEnabled = false

    btnPlay.setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View?) {
            if (mediaPlayer == null) {
                mediaPlayer = MediaPlayer.create(this@DetailActivity, Uri.parse(classAudio))
                mediaPlayer!!.isLooping = true
                mediaPlayer!!.start()
                btnStop.isEnabled = true
                btnPlay.isEnabled = false
                Toast.makeText(applicationContext,"Audio Starts",Toast.LENGTH_SHORT).show()
            } else mediaPlayer!!.start()

        }

    })

    mediaPlayer?.setOnCompletionListener {
        btnPlay.isEnabled = true
        btnStop.isEnabled = false
        Toast.makeText(this,"end",Toast.LENGTH_SHORT).show()
    }

    btnStop.setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View?) {
            if(mediaPlayer!!.isPlaying){
                stop = false
                mediaPlayer!!.stop()
                mediaPlayer!!.reset()
                mediaPlayer!!.release()
                mediaPlayer = null
                btnPlay.isEnabled = true
                btnStop.isEnabled = false
                Toast.makeText(applicationContext,"Audio Stops",Toast.LENGTH_SHORT).show()
            }
        }
    })
}
}

Solution

  • This is a classic case of onDestroy of the Activity being called. I'll keep it short but there is a lifecycle through which an Activity undergoes and when you seem to come back from the SecondActivity to the first Activity, the onDestroy of your second activity is called to perform the destruction function

    So the solution, override the onDestroy method in your DetailActivity class and do something like this

    override fun onDestroy(){
     if(mediaPlayer != null){
       mediaPlayer!!.stop()
       mediaPlayer!!.reset()
       mediaPlayer!!.release()
       mediaPlayer = null
     }
    }
    

    You can read in detail about Activity Lifecyle