Save ExoPlayer position to continue playback after closing the view (onDestroy()) - kotlin

As I have understood, when I exit the player view while watching a video by pressing or not the pause button, the onPause() and onStop() methods come into play and if we pressing back button the onDestroy() method comes into play and destroy the view.
The following code achieves that when I leave the view of the player pressing or not to the pause button, for example to increase the brightness of the screen and I return to the video, the reproduction continues for where it was left. That's good for me. But when I press the back button and play the video again, it starts from the beginning.
I could control it in the onCreate() method, but I can't find the right key.
Any idea? Thank you
private lateinit var binding: ActivityExoPlayerPlayPeliBinding
private var player: ExoPlayer? = null
private var playWhenReady = true
private var currentItem = 0
private var playbackPosition: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityExoPlayerPlayPeliBinding.inflate(layoutInflater)
setContentView(binding.root)
}
override fun onStart() {
super.onStart()
initializePlayer()
}
override fun onPause() {
super.onPause()
savePos()
}
override fun onStop() {
super.onStop()
savePos()
}
override fun onResume() {
super.onResume()
hideSystemUi()
continuePlayer(savePos())
}
override fun onDestroy() {
super.onDestroy()
savePos()
}
private fun savePos(): Long {
if (player != null){
playbackPosition = player!!.currentPosition
player!!.removeListener(this)
player!!.release()
player = null
}
return playbackPosition
}
private fun continuePlayer(playPosition: Long) {
player = ExoPlayer.Builder(applicationContext).build()
player!!.addListener(this)
binding.videoView.player = player
val url = intent.getStringExtra("url")
val mediaItem = item(url!!)
player!!.setMediaItem(mediaItem)
player!!.isCurrentMediaItemLive
playWhenReady
player!!.seekTo(currentItem, playPosition)
player!!.prepare()
player!!.play()
}
private fun initializePlayer() {
player = ExoPlayer.Builder(applicationContext).build()
player!!.addListener(this)
binding.videoView.player = player
val url = intent.getStringExtra("url")
val mediaItem = item(url!!)
player!!.setMediaItem(mediaItem)
player!!.isCurrentMediaItemLive
playWhenReady
player!!.seekTo(currentItem, playbackPosition)
player!!.prepare()
player!!.play()
}

you have to save the position elsewhere and then retrieve it in your Activity or Fragment. The easiest way to do this is through SharedPreferences

Related

How to pass Firebase Realtime database images from reyclerview to image view in another activity. KOTLIN

I have Firebase Realtime Database images displayed in a reyclerview. When users click that image, I want it to send the image to another activity's IMAGEVIEW and open that activity at the same time.
These are pictures of an example I saw on Youtube
As you can see in the second picture. It sent the data from the recyclerview to the imageview in the activity and opened that activity.
My adapter class
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>) :
RecyclerView.Adapter<AbstractAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.abstract_image_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.imageView.setOnClickListener {
val intent = Intent(mContext, PreviewActivity::class.java)
intent.putExtra("abstract", abstractList[position].abstract.toString())
mContext.startActivity(intent)
}
holder.download_btn.setOnClickListener { }
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
}
override fun getItemCount(): Int {
return abstractList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
val download_btn: Button = itemView.findViewById(R.id.abstractDownloadBtn)
}
companion object {
private const val Tag = "RecyclerView"
}
Activity to receive image
class PreviewActivity : AppCompatActivity() {
private lateinit var previewImage: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preview)
previewImage = findViewById(R.id.preview_image)
val previewImage: ImageView = findViewById(R.id.preview_image)
val bundle :Bundle? = intent.extras
val preview = bundle!!.getString("abstract")
}
Data model
class Abstract(var abstract: String? = null) {
}
I've tried running this code, but it doesn't show my image in the next activity. The Logcat doesn't give me any error, because according to it my code is running perfectly except that it's not showing the image in the next activity. I must be missing something, but I don't know what it is.
You have to set the image url to ImageView using Glide in second activity like this:
class PreviewActivity : AppCompatActivity() {
private lateinit var previewImage: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preview)
previewImage = findViewById(R.id.preview_image)
val previewImage: ImageView = findViewById(R.id.preview_image)
val bundle :Bundle? = intent.extras
val preview = bundle!!.getString("abstract")
Glide.with(this)
.load(preview)
.into(previewImage)
}

How to show user dialog box after recyclerview item click

I have an image button in my recylerview and when users click it, I want a dialog box to pop up and allow the user to edit the data in the reyclerview and save the changes.
My Adapter code
class Adapter(private var records: ArrayList<AudioRecord>, var listener: OnItemClickListener) : RecyclerView.Adapter<Adapter.ViewHolder>() {
private var editMode = false
fun isEditMode() :Boolean{return editMode}
#SuppressLint("NotifyDataSetChanged")
fun setEditMode(mode: Boolean){
if(editMode != mode){
editMode = mode
notifyDataSetChanged()
}
}
inner class ViewHolder(val binding: ItemviewLayoutBinding): RecyclerView.ViewHolder(binding.root ), View.OnClickListener, View.OnLongClickListener{
private var tvFileName : TextView = itemView.findViewById(R.id.tvFilename)
private var tvMeta : TextView = itemView.findViewById(R.id.tvMeta)
var checkbox : CheckBox = itemView.findViewById(R.id.checkBox)
val editBtn: ImageButton = itemView.findViewById(R.id.btnEdit)
init {
itemView.setOnClickListener(this)
itemView.setOnLongClickListener(this)
}
fun binding (audioRecord: AudioRecord) {
tvFileName.text = audioRecord.filename
tvMeta.text = audioRecord.duration
// checkbox.text = audioRecord.
}
override fun onClick(p0: View?) {
val position = adapterPosition
if(position != RecyclerView.NO_POSITION)
listener.onItemClickListener(position)
}
override fun onLongClick(p0: View?): Boolean {
val position = adapterPosition
if(position != RecyclerView.NO_POSITION)
listener.onItemLongClickListener(position)
return true
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(ItemviewLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
#SuppressLint("SetTextI18n", "SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (position != RecyclerView.NO_POSITION){
val record: AudioRecord = records[position]
val sdf = SimpleDateFormat("dd/MM/yyyy")
val date = Date(record.timestamp)
val strDate = sdf.format(date)
holder.binding.tvFilename.text = record.filename
holder.binding.tvMeta.text = "${record.duration} $strDate"
if(editMode){
holder.checkbox.visibility = View.VISIBLE
holder.checkbox.isChecked = record.isChecked
holder.editBtn.visibility = View.GONE
}else{
holder.checkbox.visibility = View.GONE
holder.checkbox.isChecked = false
holder.editBtn.visibility = View.VISIBLE
}
holder.binding.btnEdit.setOnClickListener {
}
}
}
override fun getItemCount(): Int {
return records.size
}
}
Summary
When users click image button. Input dialog pops up
User must be able to edit data in recyclerview and save it.
change class like this inner class ViewHolder(val binding: ItemviewLayoutBinding), var imageListener:(position:Int)->Unit)
where you call adapter , use imageListener function. Whatever you want to do you can do it inside this function. Then call it in your adapter.
in init
editBtn.setOnClickListener {
imageListener(adapterPosition)
}

Kotlin - setOnclickListener button is not working

So the Problem is, I don't know why, but the setOnClickListener is not reacting (Toasting) when I klick it.
Testet it several times and just doesn't react.
private lateinit var signInButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
initVariables()
addListeners()
}
private fun initVariables() {
signInButton = findViewById(R.id.sign_in_button)
}
private fun addListeners() {
signInButton.setOnClickListener {
println("Hello")
signIn()
}
}
private fun signIn() {
Toast.makeText(this, "Button pressed", Toast.LENGTH_SHORT).show()
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}

How to "android media player" (Kotlin)

Here's the situation - I've started studying kotlin and android studio, and now I'm stuck with this.
I have a button (ImageView) that when pressed starts to play an audio file.
class MainActivity : AppCompatActivity() {
private var mp: MediaPlayer? = null
private var bruhSound: MutableList<Int> = mutableListOf(R.raw.bruh)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
bruhBtn.setOnClickListener {
if (mp == null) {
controlSound(bruhSound[0])
bruhBtn.setImageResource(R.drawable.btnpressed)
} else if (mp !== null) {
bruhBtn.setImageResource(R.drawable.btn)
}
}
}
private fun controlSound(id: Int) {
if (mp == null) {
mp = MediaPlayer.create(this, id)
Log.d("MainActivity", "ID: ${mp!!.audioSessionId}")
}
mp?.start()
Log.d("MainActivity", "Duration: ${mp!!.duration / 1000} seconds")
}
Currently when I press "bruhBtn", the picture is changing to "btnpressed" and back again correctly, but it wont change after audio is ended. I want it to reset on the audio finishing. I realize that problem is with my code, I need to change the image when the audio is finished. How would I do this?
Before your line
mp?.start
add a listener
mp?.setOnCompletionListener { //change your button state here }

After I populate my Spinner from an asynch API call, whatever item I choose from my Spinner, I get the first one

I make a call using retrofit and RxJava to my API from my first fragment, then I display the respond I get in a Spinner. But whenever I select an item from my Spinner and click on the sendButton of my first fragment to send it to a second fragment I always receive the first item of my Spinner.
This is the code of my fragment
class SkillUpFragment : Fragment() {
val TAG = SkillUpFragment::class.simpleName
lateinit var skillsSpin : Spinner
lateinit var model : SharedViewModel
private val myCompositeDisposable= CompositeDisposable()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.skill_up_fragment, container, false)
skillsSpin = view!!.findViewById(R.id.skill_spinner)
model = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
return view
}
override fun onStart() {
super.onStart()
loadData()
}
override fun onStop() {
super.onStop()
myCompositeDisposable.dispose()
}
private fun loadData(){
val token = SharedPrefManager.getInstance(activity!!.applicationContext).loginResponse.token
val parsedJWT = JWT(token!!)
val metaId = parsedJWT.getClaim("id")
val id = metaId.asInt()
myCompositeDisposable.add(RetrofitClient.instance.getSkillsToChoose(Id(id!!))
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(this::handleResponse))
}
private fun handleResponse(skills: List<Skill>){
val skillsName = skills.map { it.name }
skillsSpin.adapter = ArrayAdapter<String>(context, android.R.layout.simple_list_item_1,skillsName)
skillsSpin.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val skill = skillsName[id.toInt()]
//When i display the value of skill before the button listener i get the right value
Log.i(TAG, skill)
frag_button_choose.setOnClickListener {
//whenever i click on the button, no matter what item i select i only from the spinner, i get always the first !!!
Log.i(TAG, skill)
model.setText(skill)
}
}
}
}
}
Please this is very confusing, i've been stuck for more than a week, any help is welcome.
Thank you all.
Select position not ID inside onItemSelected
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val skill = skillsName[position]
//When i display the value of skill before the button listener i get the right value
Log.i(TAG, skill)
frag_button_choose.setOnClickListener {
//whenever i click on the button, no matter what item i select i only from the spinner, i get always the first !!!
Log.i(TAG, skill)
model.setText(skill)
}
}
That is all