VideoView leaks activity - android

I'm showing video in an app using the following code in the VideoActivity:
binding.videoView.setVideoURI(videoUri);
binding.videoView.requestFocus();
binding.videoView.start();
binding.videoView.setOnPreparedListener(new
MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
binding.progressBar.progressOverlay.setVisibility(View.GONE);
}
});
binding.videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
binding.videoView.suspend();
binding.videoView.stopPlayback();
setResult(RESULT_OK);
finish();
}
});
binding.videoSkipButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
binding.videoView.suspend();
binding.videoView.stopPlayback();
setResult(RESULT_OK);
finish();
}
});
And after skipping / ending I get a report from leak canary that my activity:
How do I eliminate this leak?
I've also seen this question with similar leakcanary trace: VideoView memory leak
But there the problem was with ButterKnife unbinding. Do I need to do something similar with DataBinding?

Add VideoView's pause(), resume() and stopPlayback() in your activity's onPause(), onResume() and onDestroy() methods:
#Override
protected void onResume() {
binding.videoView.resume();
super.onResume();
}
#Override
protected void onPause() {
binding.videoView.pause();
super.onPause();
}
#Override
protected void onDestroy() {
binding.videoView.stopPlayback();
super.onDestroy();
}
Hope it will help you.
Thanks :)

Related

Android videoview resume not working

I have been working on playing videos using VideoView in Android.
OnPause of fragment i am pausing the video and storing the seektime
#Override
public void onPause() {
super.onPause();
if (videoview != null && videoview.isPlaying()) {
videoview.pause();
seekTime = videoview.getCurrentPosition();
}
}
OnResume i am trying to resume the video using -
#Override
public void onResume() {
super.onResume();
videoview.seekTo(seekTime);
//vvOnboardingVideos.resume();// this is not working for now - need to investigate
videoview.start();
}
The video plays from the beginning.
Is there anything i am doing wrong. Please suggest.
Try to reverse order of operations :
#Override
public void onResume() {
super.onResume();
videoview.start();
videoview.seekTo(seekTime);
}
try this:
save the video position when onpause() called
// This gets called before onPause
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
stopPosition = videoView.getCurrentPosition();
videoView.pause();
outState.putInt("video_position", stopPosition);
}
Then in your onCreate() load the stopPosition from the bundle
#Override
protected void onCreate(Bundle args) {
super.onCreate(args);
if( args != null ) {
stopPosition = args.getInt("video_position");
}
}
Resume the video using:
#Override
public void onResume() {
super.onResume();
Log.d("Tag", "onResume");
videoView.seekTo(stopPosition);
videoView.start(); //Or use videoView.resume() if it doesn't work.
}

How to play music only in foreground

I have trouble to play music across all activity, I had implement service and handle onPause to stop the music when going to background (not visible to user).
The problem is when i navigate to another activity, the onPause method is called that make my music stop. How to fix this issue? I need to play my music across all my activity in foreground only and dont wan to play it when the application in the background. Appeciate anyone know how to solve this.
This is my base activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startIntent = new Intent(getApplicationContext(), MusicService.class);
if(binder==null){
bindService(startIntent,this, Context.BIND_AUTO_CREATE);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(binder.getMyService()!=null){
stopService(startIntent);
unbindService(this);
}
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onPause() {
super.onPause();
if(binder!=null) {
binder.getMyService().pauseMusic();
}
}
#Override
protected void onResume() {
super.onResume();
if(binder!=null){
binder.getMyService().resumeMusic();
}
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MusicService.Binder) service;
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
this is my mainactivity extends base activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startIntent = new Intent(MainActivity.this, MusicService.class);
startService(startIntent);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
public void how(View view) {
Intent intent = new Intent(this, AboutActivity.class);
this.startActivity(intent);
}
You could implement code that will track current activity in your app. (Good example: How to get current activity)
And stop music only when "current activity" is null.
PS: depending on your implementation of tracking current activity you might want to check current activity not onPause() right away but with some delay .
Don't stop the audio play in onPause() as Harin Kaklotar suggested. You can use his method of onDestroy() or you can have it in an asynchronous task and turn off the sound by using surfaceDestroyed(). You can refer the android documentation of AudioManager if you need anything else of the sort.
https://developer.android.com/reference/android/media/AudioManager.html
Hope I Helped :D
UPDATE
You can create a system to check if your app is in the foreground or background. This involves counting how many activities are paused. Add this to all your activities:
#Override
protected void onPause() {
super.onPause();
MainActivity.Pause++;
}
#Override
protected void onResume() {
super.onResume();
MainActivity.Pause--;
}
And in your MainActivty,
if (Pause == NUMBER_OF_ACTIVITIES) {
//PAUSE MUSIC HERE
}
You have to use ActivityLifecycleCallbacks to tell if you app is in the foreground or background.
For example:
public class DummyActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {
#Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { }
#Override public void onActivityStarted(Activity activity) { }
#Override public void onActivityResumed(Activity activity) { }
#Override public void onActivityPaused(Activity activity) { }
#Override public void onActivityStopped(Activity activity) { }
#Override public void onActivityDestroyed(Activity activity) { }
#Override public void onActivitySaveInstanceState(Activity activity, Bundle savedInstanceState) { }
}
public class OnApplicationForegroundBackgroundEnterCallbacks extends DummyActivityLifecycleCallbacks {
private Listener listener;
private int activityStartStopCounter = 0;
public interface Listener {
public void onEnterForeground();
public void onEnterBackground();
}
public OnApplicationForegroundBackgroundEnterCallbacks(Listener listener) {
this.listener = listener;
}
#Override public void onActivityStarted(Activity activity) {
if(++activityStartStopCounter == 1) listener.onEnterForeground();
}
#Override public void onActivityStopped(Activity activity) {
if(--activityStartStopCounter == 0) listener.onEnterBackground();
}
}
Then in Application.onCreate call:
registerActivityLifecycleCallbacks(new OnApplicationForegroundBackgroundEnterCallbacks(this));

VideoView stopping on Dialog Open of anykind

I have a video view in an activity.
private void videoInit() {
videoView = (VideoView)findViewById(R.id.videoView);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
videoView.start();
mp.setLooping(true);
}
});
videoView.setVideoPath("android.resource://com.aplos.ideliver2/raw/iphone_inner_animation");//src/main/res/raw
videoView.requestFocus();
videoView.start();
}
This is my function, and the dialog is opened with an intent to the other class.
This is executed for a scenario.
private void processError(Response mResponse) {
try {
AlertDialog.strMessage = mResponse.getResponseMessage();
AlertDialog.strTitle = "Alert";
AlertDialog.strButtonTitle = "OK";
startActivity(new Intent(context, AlertDialog.class));
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
} catch (Exception e) {
H.Handle(e);
}
}
When the dialog is opened the video stops. I want to have the video running continuosly.
#Override
public void onBackPressed() {
super.onBackPressed();
videoView.stopPlayback();
}
#Override
protected void onPause() {
super.onPause();
videoView.stopPlayback();
}
#Override
protected void onResume() {
super.onResume();
videoView.start();
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
videoView.start();
}
Remove these two
#Override
protected void onPause() {
super.onPause();
videoView.stopPlayback();
}
#Override
protected void onResume() {
super.onResume();
videoView.start();
}
And add
#Override
protected void onStop() {
super.onPause();
videoView.stopPlayback();
}
#Override
protected void onRestart() {
super.onResume();
videoView.start();
}
Because onPause will be called when your window is even partially obscured, like a pop up appearing.
Edit: Since you asked me to explain why it works you need to understand the activty life cycle. OnStart() will be called when the activity is completly not visible to the user, but onPause will be called when the activity is even partially invisible, like an alert box showing on the activity, or when you pull down to see your notifications etc.
To know more about activity life cycle check this out
Use
onStop() instead of onPause()
and
onRestart() instead of onResume()
Good Luck...!

how to pause media player sound in android

I have media player in main activity. And sound start with this activity. I want when new activity start audio stop and when I press back from next activity and back to main activity audio starts. Please help me.
Code-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mp = MediaPlayer.create(this, R.raw.test);
mp.start();
mp.setLooping(true);
addListenerOnButton();
}
public void addListenerOnButton()
{
boy1 = (Button) findViewById(R.id.boy1);
boy1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
mp.stop();
startActivity(new Intent(Main.this, Boy1.class));
}
});
}
#Override
protected void onPause() {
super.onPause();
mp.stop();
}
#Override
public void onBackPressed() {
super.onBackPressed();
mp.stop();
finish();
}
#Override
public void onResume()
{
super.onResume();
}
#Override
protected void onStop() {
super.onStop();
mp.stop();
}
}
try this way:onPause()
#Override
protected void onPause() {
super.onPause();
try{
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}catch(Exception we){
we.printStackTrace();
}
}
And onResume()
#Override
protected void onResume() {
super.onResume();
try{
mediaPlayer.start();
}catch(Exception we){
we.printStackTrace();
}
}
You could use the pause() method available in MediaPlayer class. This would be useful:
http://developer.android.com/reference/android/media/MediaPlayer.html
You can do this using mediaPlayer.pause();

How to stop youtube video playing in Android webview?

How can I stop a YouTube video which is played in my webview? When I click on the back button the video doesn't stop and instead continues in the background.
Code:
webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setPluginsEnabled(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setBuiltInZoomControls(false);
webView.getSettings().setSupportZoom(false);
webView.loadData(myUrl,"text/html", "utf-8");
See the following post about WebView threads never stopping
Essentially you'll need to call the WebView's onPause method from your own Activity's onPause method.
The only trick with this is that you cannot call the WebView's onPause method directly because it is hidden. Therefore you will need to call it indirectly via reflection. The following code should get you started on setting up your own Activity's onPause method:
#Override
public void onPause() {
super.onPause();
try {
Class.forName("android.webkit.WebView")
.getMethod("onPause", (Class[]) null)
.invoke(webview, (Object[]) null);
} catch(ClassNotFoundException cnfe) {
...
} catch(NoSuchMethodException nsme) {
...
} catch(InvocationTargetException ite) {
...
} catch (IllegalAccessException iae) {
...
}
}
Note that the variable 'webview' in the try block above is a private instance variable for the class and is assigned to in the Activity's onCreate method.
Solution: 1 -
After spending lot of time, I got the conclusion to pause the video which is playing with WebView <iframe> concept of HTML.
Just override the onPause() method on Activity or Fragment whereever you used WebView, and call it. It works for me.
#Override
public void onPause() {
super.onPause();
mWebView.onPause();
}
#Override
public void onResume() {
super.onResume();
mWebView.onResume();
}
Solution: 2 -
If above solution doesn't work for you then you can force WebView to load a non existent html file.
mWebview.loadUrl("file:///android_asset/nonexistent.html");
you also have to implement the onResume() method or second time it won't work
#Override
public void onResume()
{
super.onResume();
webView.onResume();
}
#Override
public void onPause()
{
super.onPause();
webView.onPause();
}
The above solution failed for me on Samsung Galaxy S with Android 2.3.3.
But I made success trying the below workaround:
webview.loadUrl("file:///android_asset/nonexistent.html");
I am forcing the webview to load a non existent html file. This seems to be forcing the webview to clean things up.
Try this:
#Override
public void onPause() {
super.onPause();
myWebView.onPause();
myWebView.pauseTimers();
}
#Override
public void onResume() {
super.onResume();
myWebView.resumeTimers();
myWebView.onResume();
}
#Override
protected void onDestroy() {
myWebView.destroy();
myWebView = null;
super.onDestroy();
}
And here's my personal favourite:
#Override
protected void onPause() {
super.onPause();
if (isFinishing()) {
webView.loadUrl("about:blank");
} else {
webView.onPause();
webView.pauseTimers();
}
}
#Override
protected void onResume() {
super.onResume();
webView.resumeTimers();
webView.onResume();
}
It pauses the webview if the view is only paused, but clears it when the activity is finished.
This requires at least Android 3.0 - API 11 (Honeycomb)
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(keyCode==event.KEYCODE_BACK)
{
mWebview.loadUrl("");
mWebview.stopLoading();
finish();
}
return super.onKeyDown(keyCode, event);
}
it works
The above approach did not work for me, one which worked for me is :
#Override
protected void onPause() {
super.onPause();
((AudioManager)getSystemService(
Context.AUDIO_SERVICE)).requestAudioFocus(
new OnAudioFocusChangeListener() {
#Override
public void onAudioFocusChange(int focusChange) {}
}, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
Webview.loadUrl("about:blank");
it is also working
After having encountered this problem it seems that onPause might not be doing anything... for me it was not stopping whatever was playing in background.
so my code now looks like
#Override
protected void onPause() {
mWebView.onPause();
super.onPause();
}
#Override
protected void onResume() {
mWebView.onResume();
super.onResume();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
mWebView.saveState(outState);
super.onSaveInstanceState(outState);
}
#Override
protected void onDestroy() {
mWebView.destroy();
mWebView = null;
super.onDestroy();
}
Hope it helps anyone with the same problem as me
you can try this
webView.loadUrl("javascript:document.location=document.location");
if the page which is loading is one you can edit then you can write a javascript method which stop the audio and call when you want to stop like.
Javascript function
function stopAudio(){
audios=document.querySelectorAll('audio');
for(i=0;i<audios.length;i++){
audios[i].stop();
}
}
From Andorid Call this method
webView.loadUrl("javascript:stopAudio()");
if the page is not editable by you the you can inject the js code
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
injectScriptFile(view, "js/script.js");
}
How to Inject See Here in Detail
Based on #sommesh's answer:
override fun onPause() {
super.onPause()
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
if (Utils.hasOreoSDK26()) {
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.setAudioAttributes(audioAttributes)
.setAcceptsDelayedFocusGain(true)
.setWillPauseWhenDucked(true)
.setOnAudioFocusChangeListener(
{ focusChange -> Timber.i(">>> Focus change to : %d", focusChange) },
Handler())
.build()
audioManager.requestAudioFocus(audioFocusRequest)
} else {
audioManager.requestAudioFocus({ }, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
}
}
This works for me.
#Override
protected void onPause() {
super.onPause();
if (wViewCampaign != null){
wViewCampaign.stopLoading();
wViewCampaign.loadUrl("");
wViewCampaign.reload();
wViewCampaign = null;
}
}
You can do it by using the method onPause() of the of WebView when is executed the method onPause()of your Activity :
#override
public void onPause() {
super.onPause();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
webview.onPause();
}
}
works for API >= 11 (Honeycomb)
I tried all above answer , but most of them not work for me. so i just write my own solution which works fine in all type of media playing in webview
String lastUrl = "";
#Override
public void onPause() {
super.onPause();
lastUrl = webView.getUrl();
webView.loadUrl("");
}
#Override
protected void onResume() {
super.onResume();
webView.loadUrl(lastUrl);
}
#Override
protected void onDestroy() {
super.onDestroy();
webView = null;
}
This is what finally worked after trying each and every code provided on this page. Uff!
#Override
protected void onPause() {
super.onPause();
if (mWebView != null) {
mWebView.stopLoading();
mWebView.reload();
}
}
#Override
protected void onResume() {
super.onResume();
}
In my situation, the player keep running after the WebView is "onPause."
So I check if the WebView is attached to the windows before playing video or music.
It is JavaScriptInterface method for checking WebView's "isAttachedToWindow()" return true/false.
(And I didn't forget to call onPause/onResume in Activity/Fragment.)
This code works perfect for me.
#Override protected void onPause() {
super.onPause();
wv.onPause();
wv.pauseTimers();
}
#Override protected void onResume() {
super.onResume();
wv.resumeTimers();
wv.onResume();
}

Categories

Resources