I'm facing a serious problem with the Croutons Notification Library,
When i quickly switch my activites, sometimes (very often indeed) croutons for updates, like missing credentials, or "insert date first" are not shown anymore,
and so the users stay without any info, what's the problem.
For instance also the simple usecase:
Login To Application,
Logout,
try to re-login but with false credentials,
doesnt show a crouton anymore.
I tried:
Courton.clearAllNotifcations() in inPause(),
and additionally,
Crouton.clearCroutonsForActivity(this) too in onPause(),
to maybe solve the Problem, but it didn't.
I also debugged in the CroutonLibrary and the problem seems to be,
a Crouton gets added to queue, the the activity gets finished, the something finishes (like aSyncTask showing a crouton in onPostExecute(), this one gets added to the queue again, and then the queue is stuck.
Also.clearAllNotifications (which actually clears the queue) doesn't work, because the courton (asynctask finishes after acitvity.finish()) gets added afterwards, and the problem persists.
also tried:
#Override
protected void onDestroy() {
Crouton.clearCroutonsForActivity(this);
Crouton.cancelAllCroutons();
super.onDestroy();
}
knwon issue: https://github.com/keyboardsurfer/Crouton/issues/24
but didn't work too...
Thankful for any advice!
:)
You have found the correct issue on Crouton and the part of the code that is responsible for producing the issue.
In your case it correlates with the AsyncTask which is still running when your Activity actually should have been destroyed already. It's generally a good thing to move long running behavior out of user facing components, i.e. using a service layer.
Until then canceling the AsyncTask should do the trick.
thx #keyboardsurfer for the explanation...
adding...
and extracting the AsyncTask to a member variable...
#Override
protected void onPause() {
Crouton.clearCroutonsForActivity(this);
if (loadTasksTask != null) {
loadTasksTask.cancel(true);
}
super.onPause();
}
fixed the issue! :)
thx a lot :)
Related
The Situation
In the official documentation here: https://google.github.io/android-testing-support-library/docs/rules/index.html, it says:
"This rule provides functional testing of a single activity. The
activity under test will be launched before each test annotated with
#Test and before any method annotated with #Before. It will be
terminated after the test is completed and all methods annotated with
#After are finished. The Activity under Test can be accessed during
your test by calling ActivityTestRule#getActivity()."
Technically yes, the Activity is being terminated. But there doesn't seem to be any guarantee as to when this will happen. E.g. it won't necessarily happen before it's created again for the next test.
The Problem
In some of my tests, I need to rely on the fragments OnDestroy or OnDetach being called after each test, before the next test starts. I have listeners that need to be cleared and recreated.
If onDestroy from the previous test is called after OnResume in the current test, then the callback is cleared and the view doesn't get updated and the test fails.
If onDestroy from the previous test is not called at all, then the callback from the current test will be referring to the wrong instance. Again the view will not get updated and the test will fail.
The Question
Is this behaviour discussed in the situation by design or is it a bug? I'm so far unable to find this in the documentation.
What is best practice to handle this? I suspect other people have faced this problem.
Edit: I've now solved part 2. See workarounds section below. However if someone can answer part one by citing an official resource then I'd be happy to accept that answer. That's what I'm really asking here. The second part was just a bonus if someone had some ideas.
The Proof
If you would like to see this behaviour it will only take a few moments. Create a new project with an Activity like this:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
and a test class like this:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class EspressoLifecycleTest {
#Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule<>(MainActivity.class);
#Test
public void test1() {
}
#Test
public void test2() {
}
#Test
public void test3() {
}
#Test
public void test4() {
}
}
Put breakpoints on the OnResume and OnDestroy methods and run the test suite in debug mode.
Do this a few times and notice that the order the Activity life cycle methods are called is not consistent. E.g. it might call OnResume twice in a row, and then call OnDestroy once, and then OnResume twice again, and then OnDestroy three times, or any other combination you can think of. Of course it always starts with at least one OnResume. Sometimes it doesn't even call OnDestroy if it's at the very end, but that's fine. What's not fine is that my tests are flaky because of this unpredicatable order.
I'm aware that this might be intentional and there could be a simple way to deal with it, I'm just not lucky enough to have found it. Please if you know what it is, post the answer here. I don't care how dumb my question might be in hindsight, I've spent a LOT of time on this problem. It's almost always something simple so I'm prepared to be embarrassed by the answer.
Workarounds
Using onPause over OnDestroy has the side effect of being called when I startActivityForResult, but without calling onResume again in the background fragment while in tablet mode. I'm exploring ways to make this work but no solution as yet.
Edit: onPause ended up with the same problem - which is partly why I was using onDetach in the first place. Ultimately, there are times when I don't want to detach the listeners until the fragment is destroyed.
This leads me to my next idea which worked! Hooray! Up until now I was creating a callback for the calling Activity, for the thing it was asking for, only if that specific callback didn't exist. It turns out this was a bad idea. I did that so I could limit the number of callbacks to the exact number required. The motivation was sound but the implementation required all this callback clearing. The solution is to recreate every callback when ever it's called from the fragment. Don't create it if it's null, always create it and replace whatever was there before. Now there's no need to clear them at all (AFAIK).
It's a bug: http://b.android.com/201513
I use fork work around it: https://github.com/shazam/fork
Noticed this issue before and the 'solution' I can think of is to override methods in ActivityTestRule: afterActivityFinished() or beforeActivityLaunched(). Basically you want to check and wait the listeners are cleared before next test execution.
IMO, this is a bug of ActivityTestRule.
I have a few specific Questions.
I´m developing a touristic app. It works great, but after a long time launching new activities it crashes. I used the debug and i realized it uses a lot of memory, it is like the activities don´t closes altought I call.
#Override
public void onBackPressed() {
super.onBackPressed();
this.finish();
}
after removing some static variables and using in every new activity this flag
Intent.FLAG_ACTIVITY_CLEAR_TOP
memory space is relieved. App performance looks good, altought it uses a lot of images and listviews because i used Holders
However, in the main activity i placed the same onBackPressed code, but after pressing it the app is not closed, the memory usage is decreased but i have my doubts
Here is my Questions
Is the app really closing?
It still there because is a recent app?
The memory usage decreasing means that the activity FLAG_ACTIVITY_CLEAR_TOP and onBackPressed() is Working?
Is this the
right way to manage the activities to finish() ?
http://developer.android.com/training/articles/memory.html Check this out it may help you with the memory issue.
Secondly, if your app makes use of internet connection, do check out your code for checking the internet connection to be present or not.
Thirdly, it seems that you have written all the code in the onCreate() method, hence the app is taking a long time. Make use of AsyncTask.
Fourthly, whenever you call finish() method, the app closes. So it is the right way.
So I have a strange problem, and I'm not entirely sure what all information I should provide, but I'll do my best -- just let me know if I need to add more info. I'm having an issue that when I finish my Activity and return to the previous Activity (or launch it with a new Intent -- the problem seems to be centered on finishing the Activity) the UI performance drops drastically for about six or seven seconds, then returns to normal.
From LogCat, this warning appears consistently:
07-11 22:09:42.594: W/ActivityManager(292): Launch timeout has expired, giving up wake lock!
07-11 22:09:42.601: W/ActivityManager(292): Activity idle timeout for ActivityRecord{42bf6e00 com.kcoppock.sudokubeta/com.kcoppock.sudoku.SudokuBoardActivity}
As soon as the activity times out, UI performance returns to normal. Until that point it is very sluggish. I have no code that I am aware of that could be blocking the main thread, and I've even gone so far as to comment out my entire onPause() method to see if it makes any difference, and it does not.
The Activity does not spawn any background threads, does not perform any network activity, the only disk access it has is some accessing of SharedPreferences. The previous questions I've been able to locate are about idle timeouts for HistoryRecord, not ActivityRecord.
Any ideas what would cause this? Or how I could go about determining what is blocking the UI thread, if that is what is happening?
EDIT : Okay, just tried commenting out everything except super.onCreate() and setContentView() -- the problem still persists. It doesn't occur with any other Activities but this one, but there's NOTHING TO this one. :/
Oh geez. One of those things that's pretty hard to diagnose outside of trial and error, but I've figured it out. For reference, should anyone else have this problem, it came down to a custom view in my layout. I had added a ViewTreeObserver.OnGlobalLayoutListener() to do some layout modifications after the layout pass, but within that listener I modified the layout and thus caused another layout, essentially creating an infinite loop (but somehow not causing an ANR). My solution was like so:
private class BoardLayoutListener implements OnGlobalLayoutListener {
#Override
public void onGlobalLayout() {
//...do stuff here
//REMOVE this listener so that you don't repeat this forever
ViewTreeObserver obs = SudokuBoard.this.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
}
This solution is quite ironic, considering my second highest rated answer on StackOverflow specifically deals with this. :P
sigh
I've had the same issue today but as it turned out to have a different cause and solution I decided to add the information here just in case it might help someone else.
In my case problem was caused because I had the following line inside my onActivityResult() method:
android.os.Debug.waitForDebugger();
I Just deleted the line and the problem was gone.
This line is usually used to synchronize the debugger with the OS threads but I just figured it shouldn't be used anywhere. Oddly the problem would not appear until I had my phone disconnected from the desktop.
Regards
I have a problem that causes me some problems when a user (or another app, like the phone-application) pushes my application to the background.
My application does following:
A User can enter some information that is supposed to be pushed to a server.
When the user clicks "Send" i open a managed ProgressDialog and start an AsyncTask that performs the server communication.
When server communication is complete the AsyncTask reports back to my Activity where i perform a dismissDialog().
Directly after dismissDialog(), I will show another managed dialog using showDialog() that will inform the user about whether the submission was ok or if it failed.
This all works perfectly without any issues; however, when a call happens to come while the AsyncTask is running I get (seemingly random) one of these results:
The activity holding the managed dialog is dismissed completely and the previous view from the stack is presented when I come back.
The activity holding the managed dialog is still on screen, but it is grayed out without showing a dialog. The only way to fix this is to rotate the phone at which point it shows the "Submission sent"-dialog exactly the way it should and everything is ok after that.
All this happens without any warning messages so I get absolutely no clues as to why Android is behaving this way.
I know a way around this and that is to cancel the AsyncTask (so no dialogs are shown at the end). However, in this very use-case the requirements are that the app has to try to complete the server transaction so that there is as little confusion as possible (i.e. the user wondering if it was really sent or not).
Has anybody else had this issue and knows a way around?
I see recommendations to hold a reference to the asynch task in onRetainNonConfigurationInstance
What to do with AsyncTask in onPause()?
Or implement a bus:
https://github.com/commonsguy/cwac-bus/tree
EDIT: The complexity of your challenge is two fold:
1) saving and restoring state of your app on a kill such as when there is an incoming phone call
https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/saving-instance-state
2) somehow continuing the asyncTask on kill instead of canceling it onPause
https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/asynch
Both of these are significant challenges alone, and trying to fix both at the same time would give me a headache. In fact, I am getting a headache just thinking on it :) One clue is that you say the dialog returns on orientation change. This MAY be due to the fact that using the standard architecture for dialogs, the OS handles saving and restoring the state of dialogs for you on orientation change.
[EDIT] See CommonsWare
#Override
public Object onRetainNonConfigurationInstance() {
task.detach();
return(task);
}
and
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bar=(ProgressBar)findViewById(R.id.progress);
task=(RotationAwareTask)getLastNonConfigurationInstance();
if (task==null) {
task=new RotationAwareTask(this);
task.execute();
}
else {
task.attach(this);
updateProgress(task.getProgress());
if (task.getProgress()>=100) {
markAsDone();
}
}
}
where task is an instance of
static class RotationAwareTask extends AsyncTask<Void, Void, Void> {
I see no reason why this would not work for all types of soft kills, but on a hard kill, well, you get killed. Dead is dead :)
Without looking at your code it is slightly difficult to say what the problem is. However, here is something you could use to help get around the problem. You can override the onPause() method of your Activity.
This is taken directly from the Android Acitivy javadoc:
onPause() is where you deal with the user leaving your activity. Most importantly, any changes made by the user should at this point be committed (usually to the ContentProvider holding the data)
When it comes to threads and orientation changes, it seems the normal thing to do is something like this:
public class Bwent extends Activity {
private static Bwent instance;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
instance = this;
}
//...
That way, if you're making a network request with a thread, and someone changes the orientation of the phone, the thread will know to use the new Activity.
However, is it possible that the thread could finish during the time Android is destroying the old Activity and creating a new one?
Is there a moment in the process where the thread still might be pointing to the wrong Activity, or a partially destroyed activity?
It seems like there shouldn't be, but even using a Handler created in the main thread, I'm having intermittent issues with a thread trying to update an object that no longer exists. It's rare, but it does happen.
When it comes to threads and
orientation changes, it seems the
normal thing to do is something like
this:
It is a thing to do. I am not certain whether or not it is the "normal" thing to do. I am dubious that it is the best thing to do.
However, is it possible that the
thread could finish during the time
Android is destroying the old Activity
and creating a new one?
Yes. There is nothing in your code preventing it.
Is there a moment in the process where
the thread still might be pointing to
the wrong Activity, or a partially
destroyed activity?
Yes. There is nothing in your code preventing it.
Instead, try the pattern that I illustrate here. Use an AsyncTask, implemented as a static inner class or a public class. Have it be the one that knows about the Activity. Have it only use the Activity in doPostExecute() (or possibly onPublishProgress()). From the way AsyncTask and Handler work, our understanding is that the AsyncTask will always have an Activity in those on-the-main-thread methods.
Some of this stuff was discussed recently.