Android : youtube player has been released - java

I'm getting this error Fatal Exception: java.lang.IllegalStateException
This YouTubePlayer has been released , but release() wasn't called explicitly.Here is the piece of code where crash occurs :
if(youtubePlayer != null){
time = youtubePlayer.getCurrentTimeMillis();//exception may occur
}
is it possible to check that youtubePlayer was released? Any callback ? Thanks.

Most of the code in the Youtube SDK is obfuscated which makes it really hard to debug. And the fact that there isn't any direct method to check if the YoutubePlayer has been released or not doesn't help either.
Having said that I think making YoutubePlayer null (in onStop()) seems more of a hack than a proper solution to me. You should release the YoutubePlayer in onDestroy() and don't manually assign it as null anywhere. One simple approach to check if the YoutubePlayer has been released or not is put your calls (like youtubePlayer.loadVideo(), cueVideo(), getCurrentTimeMillis() etc.) in a try catch block and catch the IllegalStateException exception.
According to the Youtube SDK documentation on errors:
public static final YouTubePlayer.ErrorReason
UNEXPECTED_SERVICE_DISCONNECTION
Playback has been canceled and the player has been released due to an
unexpected disconnection from the YouTube API service. Any further
calls to this player instance will result in errors, a new player
instance must be created to re-enable playback.
So to create a new instance of the YoutubePlayer just call the initialize() method in the catch block.
Example:
public void setVideoId(final String videoId) {
if (videoId != null && !videoId.equals(this.videoId)) {
this.videoId = videoId;
if (youtubePlayer != null) {
try {
youtubePlayer.loadVideo(videoId);
} catch (IllegalStateException e) {
initialize(API_KEY, this);
}
}
}
}
#Override
public void onDestroy() {
if (youtubePlayer != null) {
youtubePlayer.release();
}
super.onDestroy();
}

I fixed this issue by making videoPlayer null in onDestroy of Activity.
Edit:
Tried in onStop and it works fine.
#MickeyTin, Thanks..

The type of variable returned by youtubePlayer.getCurrentTimeMillis(); is a int.
This should work:
if(youtubePlayer != null){
int millis = youtubePlayer.getCurrentTimeMillis();//exception may occur
}

This is how I managed to get rid of this exception. In my case it was thrown on onSaveInstanceState where I tried to save current player position using the same piece of code:
if(youtubePlayer != null){ time = youtubePlayer.getCurrentTimeMillis(); }
and upon successfull player initialization in onInitializationSuccess I continued playing video using the time value assigned in onCreate from Bundle.
But it turned out that such approach is unnecessary. To avoid the exception throw I just added android:configChanges="orientation|screenSize" attribute to my player activity in manifest. This makes the system handle orientation changes by itself, and adding time parameter to cueing the video becomes redundant. This is what checking the wasRestored flag is made for in onInitializationSuccess.
Here's the changes summary:
AndroidManifest.xml:
<activity android:name=".VideoPlayerActivity"
android:configChanges="orientation|screenSize"/>
VideoPlayerActivity.java:
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
this.mPlayer = player;
if (!wasRestored) {
mPlayer.loadVideo(mVideoId);
}
}

Related

If there is a Instruction after onDestroy , will the Instruction be executed?

Here after on Destroy I print a Log statement , will the Log get shown as the app already gets destroyed and no Instruction can be executed after app gets destroyed .
#Override
protected void onDestroy() {
super.onDestroy();
Log.v(TestActivity,"App is currntly getting destroyed")
}
So will "App is currently getting destroyed" be printed?
If it won't be printed then how can I execute code in onDestroy Method?
The answer to your question is, "It Depends".
The reference documentation says that onDestroy is not guaranteed to be called.
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
So, yes, you message will be called unless Android destroys the process first.
Documentation also say that you must call through to the super classes implementation...
If you override this method you must call through to the superclass implementation.
...but it doesn't say what order the call should be made. Because of that, I would look at Activiy source to see what it is doing. Here is the (version de jour) source code for onDestroy from Google Source.
protected void onDestroy() {
mCalled = true;
// dismiss any dialogs we are managing.
if (mManagedDialogs != null) {
final int numDialogs = mManagedDialogs.size();
for (int i = 0; i < numDialogs; i++) {
final ManagedDialog md = mManagedDialogs.valueAt(i);
if (md.mDialog.isShowing()) {
md.mDialog.dismiss();
}
}
mManagedDialogs = null;
}
// close any cursors we are managing.
synchronized (mManagedCursors) {
int numCursors = mManagedCursors.size();
for (int i = 0; i < numCursors; i++) {
ManagedCursor c = mManagedCursors.get(i);
if (c != null) {
c.mCursor.close();
}
}
mManagedCursors.clear();
}
// Close any open search dialog
if (mSearchManager != null) {
mSearchManager.stopSearch();
}
}
Though this could change at any time, we can see that onDestroy in the super class will clean up resources (as documentation says). So, does your implementation of onDestroy rely upon any of those resources? That would dictate that your code should be called before super.onDestroy(). If not, then the order doesn't matter (except that your teacher has told you what order to use).
Call the super.onDestory() after your code executed.
#Override
protected void onDestroy() {
Log.v(MainActivity,"App is currntly getting destroyed")
super.onDestroy();
}
Also it won't be called if the app destroyed by the android for memory allocation.
Its better to use onStop() method to save your data.
It is not guarantee that onDestroy() will always call. You can do your cleaning stuff in onStop() method.

IabHelper (class) Dispose (method) unhandled exception

I'm trying to implement in-app purchase in my latest android project.
To do so, I'm following this guide.
Everything went smooth until I used the dispose method in order to close any communication with the play store.
What I get is the following error:
Error:(101, 45) error: unreported exception IabAsyncInProgressException; must be caught or declared to be thrown
On the following code segment:
#Override
public void onDestroy() {
super.onDestroy();
//Always unbind the with the store connection, otherwise performance degradation of the device may follow.
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
After digging in the IabHelper class (Java) I found the dispose method.
Here the code of the method:
/**
* Dispose of object, releasing resources. It's very important to call this
* method when you are done with this object. It will release any resources
* used by it such as service connections. Naturally, once the object is
* disposed of, it can't be used again.
*/
public void dispose() throws IabAsyncInProgressException {
synchronized (mAsyncInProgressLock) {
if (mAsyncInProgress) {
throw new IabAsyncInProgressException("Can't dispose because an async operation " +
"(" + mAsyncOperation + ") is in progress.");
}
}
logDebug("Disposing.");
mSetupDone = false;
if (mServiceConn != null) {
logDebug("Unbinding from service.");
if (mContext != null) mContext.unbindService(mServiceConn);
}
mDisposed = true;
mContext = null;
mServiceConn = null;
mService = null;
mPurchaseListener = null;
}
What should I do to resolve this error?
I understand that I should catch and exception but I am not confident enough to change by myself this method in this class.
(Thanks for any help)
After more research I've found that this question was already asked and answered.
Unfortunately the question is still marked as not answered.
Here there is the link to the original question.
The solution is simple:
The file that you can get from the guide are outdated, and should be instead downloaded from github.
In the method onDestroy you should instead use the following code:
#Override
public void onDestroy() {
super.onDestroy();
//Always unbind the connection with the store, otherwise performance degradation of the device may follow.
if (mHelper != null) {
mHelper.disposeWhenFinished();
mHelper = null;
}
}
disposeWhenFinished it's a more elegant solution that works better than a dispose.

Destroy Nuance session

I have an activity that creates an "Audio" class and tries to use android Text to Speech API to read some text. If the language is not supported, it tries to use MediaPlayer to play a custom mp3 file from the server. Finally if MediaPlayer fails, it uses Nuance SpeechKit to read the text:
My problem is when I destroy the activity, I want to destroy/stop the Nuance audio too and I'm not sure how to shutdown Nuance audio.
Activity class
private Audio audio;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
audio = new Audio(this).play("my text to read");
}
#Override
protected void onPause() {
audio.pause();
super.onPause();
}
#Override
protected void onDestroy() {
audio.destroy();
super.onDestroy();
}
Audio class
private TextToSpeech tts;
private MediaPlayer player;
private Session session;
public void play(String text) {
// check if supported
if (supported) tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
else mediaPlayer(text);
}
private void mediaPlayer(String text) {
// make some queries on server to find the file url
if (queryFoundFile) {
player = new MediaPlayer();
player.setDataSource(myFileUrl);
player.setAudioStreamType(3);
player.prepare();
player.start();
} else nuancePlayer(text);
}
private void nuancePlayer(String text) {
Transaction.Options options = new Transaction.Options();
options.setLanguage(new Language("eng-USA"));
session = Session.Factory.session(activity, myServer, appKey);
session.speakString(text, options, new Transaction.Listener() {
#Override
public void onError(Transaction transaction, String s, TransactionException e) {
e.printStackTrace()
}
});
// it reaches here and nuance plays the audio
}
// these are the methods I call when the activity is paused or destroyed
public void pause() {
if (tts != null) tts.stop();
if (player != null) player.stop();
if (nuance != null) nuance.getAudioPlayer().stop(); // don't work
}
public void destroy() {
if (tts != null) tts.shutdown();
if (player != null) player.release();
if (nuance != null) nuance.getAudioPlayer().stop(); // don't work
}
If I'm using Text to Speech or MediaPlayer and if I destroy my Activity, the audio is immediately destroyed. But I can't seem to destroy the audio if is Nuance playing. It just keeps talking.
I did some debugging and the pause() and destroy() methods are being called. Also nuance.getAudioPlayer is not null and is the AudioPlayer playing. I can't find the reason why he is not stopping when I call the method stop() on him.
What is Nuance?
This is my first time using Nuance so I am not that experienced with this. Basically I see it like an alternative to the Android Text to Speech.
Nuance Developers
Why I have this on my project?
My project has 4 main languages, and I need to have a text to speech function to read some text. The problem is, android Text to Speech don't support some of these languages which Nuance support.
Why is Nuance my last option?
Because Nuance has costs. I try to use android TTS or MediaPlayer. Only if those two fail, I use Nuance. It is a last resort to read my text!
As per change log, this issue is known since a year ago and no fixed yet (as per changelog).
For temporary solution till they gave you fixed release you can do the following:
Break your text in small chunks and instead of playing complete text(as audio) at once, Queued these small text chunks into the audio player so that you audio will stop after finish playing the current chunk instead of complete text.
because as per known issue in the change log given below:
Please note this line:
However, if multiple Audios are queued for playback and stop() is called, then the next Audio will not begin playing and the queue will be cleared.
I hope this will help you.
A quick look on the nuance API shows that session.speakString(...) returns a Transaction, and a Transaction has 2 methods that might be of interest for you:
cancel() - Cancel the Transaction.
stopRecording() - Stop recording audio and complete the Transaction, if there is an ongoing recording.
Looks like cancel() is what you need.
Try setting session to null to see if the garbage collector solves the problem.

MediaPlayer or SoundPool for multiple short sounds?

The app basically allows the user to play an animal sound, voice or other sound when clicking various items. I'm trying to figure out if I'm doing this in the right way because I'm seeing some issues like this error, when the user mutes>unmutes>plays a sound:
java.lang.IllegalStateException at
android.media.MediaPlayer.isPlaying(Native Method)
public class GuessActivity extends Activity implements PopupMenu.OnMenuItemClickListener {
public static int[] ssSoundsArray = {R.raw.sbuffalo, R.raw.scamel, R.raw.scat, R.raw.schicken};
public static int[] ssVoicesArray = {R.raw.buffalo, R.raw.camel, R.raw.cat, R.raw.chicken};
MediaPlayer mMediaPlayer;
Context context;
...
}
Here's an example of how I am using MediaPlayer:
if(audio_all) {
if(mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
mMediaPlayer = MediaPlayer.create(this, R.raw.whatever);
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mMediaPlayer.release();
mMediaPlayer = null;
}
});
}
I'm doing this multiple times for different buttons etc, making sure to release() after they are done since I ran into mem issues before. So the exception is telling above is telling me isPlaying() isn't valid since MediaPlayer does not exist but for some reason it ignores if(mMediaPlayer != null)
It is necessary to stop if anything is playing since the user is free to click randomly and of course I do not want any sounds overlaying eachother.
Here's how the user mutes:
case R.id.action_toggle_sounds:
if(audio_all) {
if(mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
Toast.makeText(this,"All sounds disabled",Toast.LENGTH_LONG).show();
audio_all = false;
} else {
Toast.makeText(this,"All sounds enabled",Toast.LENGTH_LONG).show();
audio_all = true;
}
return true;
I very much appreciate any help with this, thanks a lot!
If you has not so much tracks to play (not more than 32) you can try to initialize multiple MediaPlayer instances and release() them only when app onPause()/onStop() called.
Then you will have pool of ready to use MediaPlayer's. You just have to remember which one is in use right now.
Also if you use MediaPlayer in multiple threads (not only UI thread) then you MUST use mutex (thread blocking) to avoid issues.
MediaPlayer based state machine - IllegalStateException basicly means player instance is in state when calling isPlaying() not allowed. For isPlaying() documented not allowed state is only Error state, but assume state after calling release() may be also not appropriate for this.

How to get visible beacons from the RegionBootstrap AltBeacon method

I'm using the example code on this page (http://altbeacon.github.io/android-beacon-library/samples.html) in the Starting an App in the Background section and I've got a working app.
It detects whenever a beacon is in range even on background.
The problem is I need to know which beacon is it (UUID, Major, Minor) to then match it against my local database and throw a notification with the app still on background.
The didEnterRegion(Region region) function only has a matchesBeacon method, and I've tried doing the following to identify which of the beacons is being seen but it's throwing a NullPointerException:
public class SightSeeing extends Activity implements BootstrapNotifier, RangeNotifier {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Region region = new Region("sightRegion", null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
BeaconManager.getInstanceForApplication(this).getBeaconParsers().add(
new BeaconParser(). setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")
);
BeaconManager.getInstanceForApplication(this).setRangeNotifier(this);
}
#Override
public void didEnterRegion(Region region) {
regionBootstrap.disable();
BeaconManager.getInstanceForApplication(this).setRangeNotifier(this);
try {
BeaconManager.getInstanceForApplication(this).startRangingBeaconsInRegion(region);
}
catch (RemoteException e) {
Log.e(TAG, "Can't start ranging");
}
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Iterator<Beacon> beaconIterator = beacons.iterator();
while (beaconIterator.hasNext()) {
Beacon beacon = beaconIterator.next();
//check if beacon exists in our DB and throw notification
}
}
}
Am I missing something obvious or isn't this possible with this library?
EDIT:
I've updated the code sample to give you guys a broader idea and I've tried implementing the suggestion by FOliveira without any success.
EDIT2:
Updated code to reflect the davidgyoung's suggestion. Still no luck. I have a Log.d() right on the first line of the didRangeBeaconsInRegion() function and it isn't being called.
I've tried adding BeaconManager.getInstanceForApplication(this).setRangeNotifier(this); before the try/catch block and the result is the same.
Did I implement the suggestion wrong or is there any other way to get this working?
If you want the app to launch itself on beacon detection, then the RegionBootstrap is the easiest way to go. In order to combine this with Ranging needed to detect individual beacons, then add code in your didEnterRegion method like this:
try {
BeaconManager.getInstanceForApplication(this).startRangingBeaconsInRegion(region);
}
catch (RemoteException e) {
Log.e(TAG, "Can't start ranging");
}
Then implement a ranging callback like you have.
You also need to remove the code below, which is probably what is causing your NullPointerException, because the :
for(int i=0; i< beaconsList.size(); i++) {
Beacon b = new Beacon.Builder()
.setId1(beaconsList.get(i).get("uuid"))
.setId2(beaconsList.get(i).get("major"))
.setId3(beaconsList.get(i).get("minor"))
.build();
if(region.matchesBeacon(b)) {
//get info from DB and throw notification
}
}
EDIT: I have updated the library's reference application to show how this can be done successfully. See here: https://github.com/AltBeacon/android-beacon-library-reference/blob/master/src/org/altbeacon/beaconreference/BeaconReferenceApplication.java
you can implement RangeNotifier interface and you can access all the beacon information captured in the public void didRangeBeaconsInRegion(Collection<Beacon> Beacons, Region region) method of that interface. Hope i got the question right

Categories

Resources