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.
Related
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.
We are using RealChangeListener to listen data changes and updating listview by calling notifydatasetgchanged().
Initial sync time we do get many records from server(per batch 100 records), loop thru results updating Realm like below in background thread.
for(int i=0;i<results.size();i++)
{
// processing and validation
....
db.beginTransaction();
db.copyToRealm(processedObject);
db.commitTransaction();
}
In activity, we are registered realmResults change listener like below code
#Override
public void onStart() {
super.onStart();
mEntityDataProvider = new EntityDataProvider();
mEntityDataProvider = mEntityDataProvider.getListAsync();
mEntityDataProvider.addChangeListener(realmEntityChangeListener);
}
private RealmChangeListener<RealmResults<Entity>> realmEntityChangeListener = new RealmChangeListener<RealmResults<Entity>>() {
#Override
public void onChange(RealmResults<Entity> realmResults) {
if (mEntityListAdapter!= null) {
mEntityListAdapter.setData(realmResults);
mEntityListAdapter.notifyDataSetChanged();
}
}
};
Questions:
Is it best practice to call notifyDataSetChanged() in
reamlChangeListner?
For every commitTransaction() i think
realmChangeListener will be called, calling notifyDataSetChanged() calling many times is it fine?
If above practice is not good to do,
suggest me if any alternatives I need to consider.
Thanks
Yes
I think you can put the loop between beginTransaction()/commitTransaction() to avoid refresh the UI too many times.
See https://realm.io/docs/java/latest/#adapters, You can just use the adapters from Realm. And in the mEntityListAdapter.setData(realmResults); doesn't seem to be necessary to be called every time if the it is on the same RealmResults.
I was recently reading about design patterns and especially about low coupling and delegation.
I was wondering, whether there should be any logic on the Activity class or if it only serves the view.
E.g. I have an activity called BattleActivity and that is supposed to work as some kind of session between two players. A lot of Push Notifications happen there, also the class works as an Observer, so there is a lot of comminication going on there.
Right now I am trying to figure out what logic could I move to a separated object(and whether I should) and then just work with the activity.
Example of one of my methods on the activity:
private void postCastedSpell(final int spellId) {
Call call = StaticGlobalContainer.api.postSpellToBattle(Integer.parseInt(battleId), Integer.parseInt(MainActivity.CURRENT_USER_ID), spellId, 100);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Response<User> response, Retrofit retrofit) {
User user = response.body();
if (response.code() == 202) {
// 200
Log.i("Posting spell to battle", "Success");
Boolean affectedUserIsOpponent = isUserOpponent(user);
if (affectedUserIsOpponent && user.currentHp<1){
StaticGlobalContainer.battleOnResult(Constants.WON, getApplicationContext());
}else {
updateBattleLog(affectedUserIsOpponent, user, spellId);
}
// TODO: do something here
} else {
// 404 or the response cannot be converted to User.
Log.e("Posting spell to battle", "Error:" + response.errorBody());
}
}
#Override
public void onFailure(Throwable t) {
Log.i("HttpRequest-Post spell", "Failure");
}
});
}
It's not specifically bad to put a lot of logic in Activities, but you're right to try to keep it only view related things. If the app is relatively small, it might not be worth moving the logic out. Also, there is some overhead to using abstractions.
if your abstractions aren't supplying a significant benefit, you should avoid them
I try to keep any big data objects in a manager class, so given your example, it might worthwhile to create a Battle manager class to hold all the logic involved in it, like this postCastedSpell function. This way all the Battle information is self contained, and also can be used elsewhere in other activities.
Just keep in mind if you're use data manager classes and you want them to prompt some sort of interation with the UI, you'll have to use Callbacks or the Bus pattern since the Battle manager won't have access to your UI. For example, to call the postCastedSpell the call would look like:
BattleActivity:
BattleManager bm = BattleManager.getInstance(user1, user2);
onSpellClicked() {
bm.castSpell(spellId, user1, callback)
}
BasicCallback callback = new BasicCallback() {
#Override
onComplete() {
if (MyInfoFragment.this.isVisible()) {
[Update UI]
}
}
};
NOTE: When using callbacks like my example, when it finally gets called the activity may have already gone out of view and have been already garbage collected. So in the callback function you need to first make sure it is still visible before trying to modify the UI that possibly no longer exists.
My Activity is implementing OnInvitationReceivedListener along with all the other game services items. It requires that I have the onInvitationReceived function implemented (i.e. gives an error if I don't) so that's good. The problem is, I can send my account an invite and it will not call the onInvitationReceived function. The other listeners work and I can start a game and whatnot by opening the invitation list and accepting it, but this function simply never gets called. It should also consume the event but I still get an external notification as well.
Am I missing something? Is it not as simple as the below? All the other listeners work...
public class MyActivity extends BaseGameActivity
implements View.OnClickListener, RealTimeMessageReceivedListener,
RoomStatusUpdateListener, RoomUpdateListener, OnInvitationReceivedListener
{
public MyActivity(){...}
...
public void onInvitationReceived(Invitation arg0)
{
Log.v("meh", "Invitation Received");
}
}
Are you registering MyActivity for the callback?
Since you are using BaseGameActivity, try putting this in your post-connection callback:
getGamesClient().registerInvitationListener(this);
I'm somewhat surprised that this isn't done for you, but in looking at the BaseGameActivity class I don't see it.
I was having similar issues. (I still haven't cracked the code on the invite Bundle not being null everytime I start up the service... even when there are invitations waiting...)
From here Previous StackOverflow issue for Invitaion Listener I did get the issue mostly solved. (in that i do get notifications in my app code that a new invite has come in) However, there is nothing to tell you if an invite has been rescinded...
So, I also run a Timer and do this in my code:
#Override
public void loadInvitations(){
mHelper.getGamesClient().loadInvitations(new OnInvitationsLoadedListener() {
#Override
public void onInvitationsLoaded(int statusCode, InvitationBuffer buffer) {
dLog("invitations loaded " + buffer.getCount());
if(mHelper.getGamesClient().STATUS_OK == statusCode && buffer.getCount() > 0){
if(mGHInterface != null){
mGHInterface.haveInvitations(buffer.getCount());
}
} else if (mGHInterface != null){
mGHInterface.haveInvitations(0);
}
}
});
}
Up to you on how often you want to run this, but this way I have found that at least I do know if invitations exist or not, and update my app's actions accordingly.
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)