Acess to pip Activity From Another Activity - android

How Can i access to methods and finish my picture in picture activity from MainActivity
for example i want to pause videoplayer on pip mode from MainActivity:
VideoPlayerActivity().pauseVideo()
VideoPlayerActivity (Pip):
fun pauseVideo() {
player?.pause()
}
but it not working
I expected the video to stop but nothing happens

When you try to call VideoPlayerActivity().pauseVideo(), you are creating a new VideoPlayerActivity class and it will call that new class pauseVideo() instead of the original displaying class pauseVideo().
One suggestion can be creating a separate Singleton class, so that you can access your Player functions from any Activity.
class PlayerHelper {
companion object {
private var instance : PlayerHelper? = null
// Define your necessary Player tool
fun getInstance(): PlayerHelper {
if (instance == null) {
instance = PlayerHelper()
}
return instance!!
}
}
fun start() {
// Implement to start your player
Log.i("PlayerHelper", "start:")
}
fun pause() {
// Implement to pause your player
Log.i("PlayerHelper", "pause:")
}
}
And you can call pause() in any Activity like:
PlayerHelper.getInstance().pause()

Related

Android Kotlin App crash after leaving a fragment that receives a callback from an API, when the callback didn't finish

I'm using retrofit2 and coroutines, I have a fragment A and B. I made the callback to fill a recyclerView at fragment B but if the user goes back to fragment A before the callback is finished, the app crashes because there is no B fragment to receive the data.
Of course, I can disable the back button until I receive the data from the callback, but I'm sure there is a better solution.
I found a navController class removeOnDestinationChangedListener, but I'm not sure how to use it or if it may help me with this problem.
Any Ideas?
main declarations inside the Fragment:
private lateinit var binding: FragmentShowCustomerBinding
var process: Job? = null
var productHistory: ArrayList<ProductHistory> = arrayListOf()
val producthistoryAdapter: ProductHistoryAdapter = ProductHistoryAdapter(arrayListOf())
This is how I call the service:
private fun loadCustomerActivity() {
process =
CoroutineScope(Dispatchers.IO).launch {
MainService.getCustomerOrders(customer.documentNumber, 1)
{ customerActivity ->
productHistory = customerActivity
CoroutineScope(Dispatchers.Main).launch {
binding.progressBarCustomerPurchaseHistory.visibility = View.INVISIBLE
binding.recyclerViewProductHistory.let {
producthistoryAdapter.loadCustomerhistory(productHistory)
producthistoryAdapter.notifyDataSetChanged()
}
}
}
}
}
and this how I cancel it just in case the user get out from the fragment before I get the customer history:
override fun onStop() {
super.onStop()
process?.cancel()
}

Higher Order Function return null

I'm going to MenuFragment from MainActivty and calling RecyclerViewAdapter inside in MenuFragment class to set my data to show . then I want to set the callback in my Adapter using higher order function (Kotlin language) to send the data to MainActivity to change something in BottomNavigationView UI.
MainActivty class:
val callbackFromAdapter=RecyclerAdapterInside(null,null,this,::callbackAdapterInside)
private fun callbackAdapterInside(OrderList:MutableList<OrderLive>)
{
var totalSum=0
for(elements in OrderList)
{
totalSum+=elements.getcount()
}
Log.d("oncell", "$totalSum")
if(totalSum>0)
{
CoroutineScope(Dispatchers.Main).launch {
badge_current_order.visibility=View.VISIBLE
badge_current_order.setText(totalSum)
}
}
else
CoroutineScope(Dispatchers.Main).launch {
badge_current_order.setText(0)
badge_current_order.visibility=View.GONE
}
}
RecyclerAdapterInside class:
class RecyclerAdapterInside(
PlaceId:String?=null, var myReceivedData: List<ItemClass>?=null, val context:Context,
val CurrentCartUpdateCallback: ((OrderList: MutableList<OrderLive>) -> Unit?)? = null):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
...
CoroutineScope(Dispatchers.IO).launch {
if(CurrentCartUpdateCallback!=null) { //never pass this condition
CurrentCartUpdateCallback!!(myOrderLive)
Log.d("tagtest", "Callback is called ")
}
}
}
I said I'm using RecyclerAdapterInside in my MenuFragment class to set data.
recyclerview.adapter=RecyclerAdapterInside(
id,
result,
this#MenuFragment.requireContext(),
null
)
for this reason I should create the type of null for CurrentCartUpdateCallback variable. Because I never use this callback in MenuFragmentClass and I always pass null when I don't need callback in this class. so I just use it in MainActivity class.
The problem is callbackAdapterInside is never called and CurrentCartUpdateCallback is always null in:
if(CurrentCartUpdateCallback!=null)
I don't use higher order function much. Do I have to use this callback in order of class numbers
Adapter->3->2->1 or can I use callback directly from the adapter class to the Main activity class ?

When will onCompletion be launched in MediaPlayer?

I try to use the following code to play music.
I know I need to release mediaPlayer as soon as possible if I don't use it again, so I place the release code in onCompletion.
1: Will onCompletion be launched after a music have finished play?
2: Will onCompletion be launched after I invoke mediaPlayer?.stop()?
3: Will onCompletion be launched if the Activity which invoke PlayHelper is destroied?
Code
class PlayHelper private constructor(): MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener {
private var mediaPlayer: MediaPlayer? = null
fun play(path: String){
mediaPlayer= MediaPlayer()
mediaPlayer?.setAudioAttributes(
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
)
mediaPlayer?.setDataSource(path)
mediaPlayer?.setOnPreparedListener(this#PlayHelper)
mediaPlayer?.prepareAsync()
}
fun pause(){
mediaPlayer?.pause()
}
fun stop(){
mediaPlayer?.stop()
}
/** Called when MediaPlayer is ready */
override fun onPrepared(mediaPlayer: MediaPlayer) {
mediaPlayer.start()
}
override fun onCompletion(mediaPlayer: MediaPlayer) {
if (mediaPlayer.isPlaying) {
mediaPlayer.stop();
mediaPlayer.release()
}
}
companion object {
// For Singleton instantiation
#Volatile private var instance: PlayHelper? = null
fun getInstance() = instance?: synchronized(this) {
instance?: PlayHelper().also { instance = it }
}
}
}
Regarding the official documents, onCompletion is called only when the end of a media source is reached during playback. So, in other cases, like calling mediaPlayer.stop(), it won't be called.
1: Will onCompletion be launched after a music have finished play?
It will.
2: Will onCompletion be launched after I invoke mediaPlayer?.stop()?
It will not.
3: Will onCompletion be launched if the Activity which invoke PlayHelper is destroied?
It will not. The PlayHelper will be removed from memory when the Activity is destroyed.
This link: onCompletionListener from the docs contains the following line:
Called when the end of a media source is reached during playback.

How to close activity from class with context usage?

I created another class where I have function of logout:
fun logOut(context: Context) {
context.stopService(Intent(context, CheckNewMessages::class.java))
val intent = Intent(context, LoginScr::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP and
Intent.FLAG_ACTIVITY_NEW_TASK and
Intent.FLAG_ACTIVITY_NO_ANIMATION
context.startActivity(intent)
(context as Activity).finish()
}
and as you can see I use this line for finishing activity:
(context as Activity).finish()
But it is still alive and as a result I have two or more same activities at my system. I tried a lot of ways like creating static variable at first activity and using this variable at the second one for closing. But my activity stays alive. I also tried to use lauchmode at manifest and some other ways. Maybe someone knows where I did a mistake?
UPDATE
Two places from which I call logOut(). 1st is interface between RV adapter and fragment:
override fun finish() {
APICallRequests.logOut(context!!)
activity!!.finishAffinity()
}
and 2nd at Interceptor for requests:
private fun updateAccessToken(context: Context) {
val sp = context.getSharedPreferences(Constants.SHARED_PREFS_STORAGE, 0)
synchronized(this) {
val tokensCall = accessTokenApi()
.getNewToken(ReqAccessToken(sp.getString("refresh_token", "")!!))
.execute()
if (tokensCall.isSuccessful) {
} else {
when (tokensCall.code()) {
500 -> {
val thread = object : Thread() {
override fun run() {
Looper.prepare()
Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
Looper.loop()
}
}
thread.start()
}
401 -> {
APICallRequests.logOut(context)
}
}
}
}
}
That's not the way it works. What happens is this. When you do:
context.startActivity(intent)
This doesn't start the new Activity immediately. It just requests that Android starts the new Activity when it gets control back. Then you do this:
(context as Activity).finish()
This call just finishes the current Activity. When you eventually return control to the Android framework, it will launch the new Activity as you requested in your call to startActivity().
If you want your app to exit (ie: all activities finished), you can just do:
(context as Activity).finishAffinity()
This call will finish the current Activity and all other activities in the task that belong to the same app.
NOTE: This only works if all activities in your app share the same affinity, which is the default case.
try to pass Activity instead of Context in inner param fun logOut(activity: Activity), this should help you if you are calling this function from activity. If you calling it from fragment you can use requareActivity.finish()

How to check if any activity is currently opened or not

In my android application from my background service I want to launch activity with transparent background. Because of the fact that the application is transparent I always want it to be displayed on some other activity from my application. So before the launch I would need to somehow check if any activity is currently opened and if it isn't then open home activity and after that my transparent activity. But if application was already opened then I want to open new activity on top of most recent one.
How could I achieve that? Only thing I found is how to check if my application is in foreground or not. But when my app is in background I would still like to open my transparent activity atop most recent activity.
class FirebaseDbApplication : Application() {
override fun onCreate() {
super.onCreate()
}
companion object{
private var sIsChatActivityOpen = false
fun isChatActivityOpen() : Boolean {
return sIsChatActivityOpen
}
fun setChatActivityOpen(isChatActivityOpen: Boolean) {
this.sIsChatActivityOpen = isChatActivityOpen
}
}
}
// In your activity
override fun onResume() {
super.onResume()
FirebaseDbApplication.setChatActivityOpen(true)
}
override fun onPause() {
super.onPause()
FirebaseDbApplication.setChatActivityOpen(false)
}
// For checking is activity is opened or not
if (FirebaseDbApplication.isChatActivityOpen()) {
// Activity is opened
}
else{
// Activity is closed
}

Categories

Resources