IabHelper (class) Dispose (method) unhandled exception - java

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.

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.

meaning of RuntimeException("Stub!") in Android

I was surfing in Android code because I wanted to see what is into Activity.finish() method.
I just wanted to have the confirmation that in Activity.finish() there would be a call to onDestroy() method.
But what I found in this method (and in many others) was:
public void finish() {
throw new RuntimeException("Stub!");
}
So WHERE Can I find the code that really destroys the Activity?
Thanks!
This is because source code is not found in SDK.
To see the source code, you need to download source for Android SDK, so Android studio can display the respective code.
I don't know where you looked, but the code for finish() is this
/**
* Call this when your activity is done and should be closed. The
* ActivityResult is propagated back to whoever launched you via
* onActivityResult().
*/
public void finish() {
finish(DONT_FINISH_TASK_WITH_ACTIVITY);
}
which calls the private implementation
/**
* Finishes the current activity and specifies whether to remove the task associated with this
* activity.
*/
private void finish(int finishTask) {
if (mParent == null) {
int resultCode;
Intent resultData;
synchronized (this) {
resultCode = mResultCode;
resultData = mResultData;
}
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
try {
if (resultData != null) {
resultData.prepareToLeaveProcess(this);
}
if (ActivityManagerNative.getDefault()
.finishActivity(mToken, resultCode, resultData, finishTask)) {
mFinished = true;
}
} catch (RemoteException e) {
// Empty
}
} else {
mParent.finishFromChild(this);
}
}
Important here is ActivityManagerNative.getDefault().finishActivity which you can find at line 3359 in this file https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ActivityManagerNative.java
If you want to dive deeper, you can just follow the trail.
You are checking in .class not .java file.

Android VPN Service Builder.establish() returns null

I am trying to make a VPN Service work on android.
To do this, I think I have to use the Builder class provided in the VpnService class, which is provided by the android SDK. Now when I try to do this, the method
builder.establish()
returns null. Here is the full method I wrote;
// If theInterface still exists from last time, reuse it, it has the same parameters.
if (theInterface != null) {
return;
}
// configure the VPN settings.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("10.0.2.0", 32);
builder.addRoute("0.0.0.0", 0);
try {
theInterface.close();
} catch (Exception e) {
// Ignore
}
theInterface = builder.establish();
Log.i(TAG + "IMPORTANT", builder.toString());
The code crashes at:
Log.i(TAG + "IMPORTANT", builder.toString());
When debugging, the debugger says 'theInterface = null' throughout the entire execution of the program.
EDIT:
I have looked trough the Builder class which is located in android.net.VpnService
In this class, it seems that there is a hidden class (IConnectivityManager), maybe my problem has something to do with this...
Here is the piece of code I'm talking about.
/**
* Use IConnectivityManager since those methods are hidden and not
* available in ConnectivityManager.
*/
private static IConnectivityManager getService() {
return IConnectivityManager.Stub.asInterface(
ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
}
as VpnService.Builder.establish documents:
Returns ParcelFileDescriptor of the VPN interface, or null if the
application is not prepared.
need call VpnService.prepare: http://developer.android.com/reference/android/net/VpnService.html#prepare(android.content.Context) first

Android : youtube player has been released

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);
}
}

Prevent AsyncTask from running multiple times in bindView

I have a custom CursorAdapter that is using multiple AsyncTasks in its bindView method to load images into a grid.
When bindView runs my AsyncTasks get launched multiple times. This has the effect of pushing up my heap size and can cause Out of Memory errors.
What is the best approach to take, to get AsyncTasks to run just once?
You can cache the results of the Asynctask. There is a very useful project on Github you might want to look into.https://github.com/nostra13/Android-Universal-Image-Loader
I think you are looking for AsyncTaskLoader or its support package implementation. It handles everything for you.
An example of how to use it:
public SampleLoader extends AsyncTaskLoader<List<SampleItem>> {
// We hold a reference to the Loader’s data here.
private List<SampleItem> mData;
public SampleLoader(Context ctx) {
// Loaders may be used across multiple Activitys (assuming they aren't
// bound to the LoaderManager), so NEVER hold a reference to the context
// directly. Doing so will cause you to leak an entire Activity's context.
// The superclass constructor will store a reference to the Application
// Context instead, and can be retrieved with a call to getContext().
super(ctx);
}
/****************************************************/
/** (1) A task that performs the asynchronous load **/
/****************************************************/
#Override
public List<SampleItem> loadInBackground() {
// This method is called on a background thread and should generate a
// new set of data to be delivered back to the client.
List<SampleItem> data = new ArrayList<SampleItem>();
// TODO: Perform the query here and add the results to 'data'.
return data;
}
/********************************************************/
/** (2) Deliver the results to the registered listener **/
/********************************************************/
#Override
public void deliverResult(List<SampleItem> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
releaseResources(data);
return;
}
// Hold a reference to the old data so it doesn't get garbag ecollected.
// We must protect it until the new data has been delivered.
List<SampleItem> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, deliver the results to the
// client. The superclass method does this for us.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
/*********************************************************/
/** (3) Implement the Loader’s state-dependent behavior **/
/*********************************************************/
#Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Begin monitoring the underlying data source.
if (mObserver == null) {
mObserver = new SampleObserver();
// TODO: register the observer
}
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
#Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
#Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
// The Loader is being reset, so we should stop monitoring for changes.
if (mObserver != null) {
// TODO: unregister the observer
mObserver = null;
}
}
#Override
public void onCanceled(List<SampleItem> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<SampleItem> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
/*********************************************************************/
/** (4) Observer which receives notifications when the data changes **/
/*********************************************************************/
// NOTE: Implementing an observer is outside the scope of this post (this example
// uses a made-up "SampleObserver" to illustrate when/where the observer should
// be initialized).
// The observer could be anything so long as it is able to detect content changes
// and report them to the loader with a call to onContentChanged(). For example,
// if you were writing a Loader which loads a list of all installed applications
// on the device, the observer could be a BroadcastReceiver that listens for the
// ACTION_PACKAGE_ADDED intent, and calls onContentChanged() on the particular
// Loader whenever the receiver detects that a new application has been installed.
// Please don’t hesitate to leave a comment if you still find this confusing! :)
private SampleObserver mObserver;
}
The source: androiddesignpatterns.com - Implementing Loaders (part 3)

Categories

Resources