Android Fragments onStart seems to start his Code before onCreateView - android

I got a fragment, that should create some files, iterate through the contactbook and some other pretty long tasks.
The fragment is a pretty simple "Hey, please wait" fragment with a label and a progressbar. I used factory pattern to pass arguments to this fragment.
My fragments code is comparable to the solution of this question, only with other parameters and members. In the onStart-method I want to do my long tasks, but strangely it starts the code before I see my view, which should be created by the onCreateView-method first, if I remember the Fragment-lifecycle correct.
Is this a side effect of Factory Pattern or what am I missing here? What would be the best solution here, so that the view is actually shown before he starts my long code execution?

OnStart is called when the activity is becoming visible to the user. onCreateView will create your view but its not visible yet. You should start your long operation in onResume.

Please refer to http://developer.android.com/reference/android/app/Activity.html#onResume()
Basically as Nauman mentioned, often an indication that your activity is ready to be interacted by the user is the onResume. but ideally, use
onWindowFocusChanged(boolean hasFocus)
but keep in mind that this is not part of the normal lifecycle event flow. This method can be also called when dialogs come up in front of the Activity etc
see http://developer.android.com/reference/android/app/Activity.html#onWindowFocusChanged(boolean)

Related

Android app widget SeekBar progress survives onDestroy()

I have started studying Android programming recently after taking a very long break (half a decade) from programming altogether. It's been going well so far.
I have noticed that Seek Bar's progress survives onDestroy event after a rotation (configuration change) happens and this happened on a fragmented activity. Then I created an empty activity and added the widget in the layout and the result is the same (as I expected but still tried due to some code). I also tried overriding the onCreate method and passing a null SavedBundleInstance into super.onCreate() and the result is the same. So I don't know where the Seek Bar's progress location is saved before onDestroy and then passed back unless I am missing some static variable in the SeekBar class or its super classes. (I just thought about that now, I should check it)
Can someone explain why this happens?
Usually, Android Views save their state upon rotation. The same happens for example with EditText. If you input something and then rotate the device, the text will be kept.
It's done inside the specific View class.
But how is this state persisted through orientation changes?
In Activities, for example, you have onSaveInstanceState(Bundle bundle). That method is called by the system before a configuration change occurs. What you do, to persist the state of the Activity, is to store inside bundle the values you want to save. Then, when the Activity is created again, this bundle is passed back to you, for example in the onCreate method. This way you can restore your state.
But what about Views? They use a similar mechanism. If we want the details we have to look at the source code. Let's look at the source code of ProgressBar. It turns out that the View has a onSaveInstanceState, too (this line). You can see there, that the progress is being saved.
I hope this clarifies the mechanism.

I have a trouble in Fragment life cycle and need a resolution to come out of it

I have done ample research on this, and there is not one clear solution on the problem.
In the life-cycle, particularly in the Fragment life-cycle, following Exception comes any moment after onPause().
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
My logic says, that to continue with the current fragment, after it reaches this state, I have to restart the activity and again point back to the intended fragment using Intent.
I want to be clear on what is happening and what should be real solution to deal with it.
I need to know the pros and cons of this mechanism; its importance in Fragment or Activity life-cycle.
Also, if I am changing the Windows Feature in onCreate to not to go to sleep, unless if the user has manually pressed the home button, will still the activity will go to this state?
This exception happens when you're trying to add/remove/replace/interact in any other way with a Fragment inside the Activity when it's paused.
Which means Activity will not be able to restore it's state (restore the state of a Fragment which has been changed) if it will be destroyed right away.
Best solution here, is to check that Activity is NOT paused during the interaction with a Fragment.
Another option is to use commitAllowingStateLoss() to interact with Fragment transaction, with a risk of losing it's state.
See:
https://developer.android.com/reference/android/app/FragmentTransaction.html#commitAllowingStateLoss()
In a perfect world you should analyze each crash carefully and add checks to verify that you interact with fragments only when Activity is up and running.
A better explanation is presented in a new Android developer reference and guide documents for using JetPack Life Cycle Listener.
https://developer.android.com/topic/libraries/architecture/lifecycle#kotlin
The library makes the components Activity Life Cycle aware. That means you do not require an abstract baseActivity class which overrides every life cycle callback, and record that state in a boolean variable. LifeCycle listener will do it for you.
All you have to do is stop introducing a new fragment or stop any Loader that updates the UI when its response returns. The right time to do this is before onStop or onSavedInstance state is called, and your components will be made aware of it.
It clearly states that after the onSavedInstancState or onStop is called the UI becomes immutable till the onStart of the Activity is called again. Sometimes you have to call restart the same activity using NEW TASK and CLEAR TASK flags using intent, when this state occurs and there is no chance that otherwise onStart is going to be called.
Happy Coding :-)

Invalidate is failing to call onDraw when returning to an activity that has a custom view

I have inherited some code hence I don't have true freedom to change it. :(
I have a main activity, from which other activities (I will refer to these as sub activities from now on) are called. Whenever one of these completes, it calls finish and returns data to the main activity.
Each activity (including the main one) has a bar on the top that displays a custom view. The custom view contains a canvas which has a drawing that is dependant upon the state of the network.. i.e. wifi/mobile etc...
Since that 'state' data never changes, it's held within a singleton and the view gets data from the singleton to define what it draws. That is working with no issues, i.e. the data is always as I expect it.
When I first launch the MainActivity, as the network changes, the data changes and each call to 'invalidate' the view receives a system call to 'onDraw' as I would expect.
In each of the sub activities the same is again true.
Upon finishing a sub activity and returning to the mainActivity, calls to invalidate no longer cause a call to onDraw to occur.
I have looked at this for quite a while now and just cannot figure out what is going wrong.
In my constructor I have:
setWillNotDraw(false);
Whenever the data changes the following methods are called:
invalidate();
requestLayout();
Now, there's one more thing... upon returning to the activity at that immediate point, I refresh and this DOES draw correctly, i.e. invalidate does trigger an onDraw call... any subsequent network changes (which are propogated) fail to result in the onDraw call.
I'm wondering if this is to do with the view somehow being detached. I can see that 'onDetachedFromWindow' is called, however the trigger for this is the destruction of the subactivity, hence I don't see why that should affect the MainActivity but it's the only thing I can think of.
I'm hoping I've provided enough information for someone to help me...
Well, in the end my answer has very little to do with the question and I guess this is an example of how an issue can be solved by going back to absolute basics and checking for the obvious.
My activities all inherit from an abstract activity. Within that activity there is an instance of the view. The views in which I was having trouble were using that declaration as opposed to having their own instance, hence behaviour from one activity was then affecting another inadvertently.
So, if I'd been able to post up all the code, I'm sure someone else would have spotted this but, unfortunately I couldn't in this instance.
Still, whilst this posting doesn't provide a resolution that will help others, maybe it does say... step back and check the obvious first!

Android Activity Test: How to Force Refresh

I need to test that my activity will reconfigure the view properly at different times of day. I injected a TestClock, but of course, there's no way to do that until the activity has already been created by calling getActivity().
So I have a method I invoke on the Activity.
It updates the view properly. However, I spent hours trying to figure out why a button that should have been visible was not. Then I figured out that the view had not been refreshed, so I introduced a sleep into the test and it passed.
Question:
there has to be a simple way to tell the Activity to refresh the view so you can assert the results of your changes?
If you want to test UI thread, you have to use waitForIdleSync. Refer this for more info.

Android lifecycle: Fill in data in activity in onStart() or onResume()?

Should you get data via a cursor and fill in the data on the screen, such as setting the window title, in onStart() or onResume()?
onStart() would seem the logical place because after onStart() the Activity can already be displayed, albeit in the background. Notably I was having a problem with a managed dialog that made me rethink this. If the user rotates the screen while the dialog is still open, onCreateDialog() and onPrepareDialog() are called between onStart() and onResume(). If the dialog needs to be based on the data you need to have the data before onResume().
If I'm correct about onStart() then why does the Notepad example give a bad example by doing it in onResume()? See http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html NoteEditor.java line 176 (title = mCursor.getString...).
Also, what if my Activity launches another Actvity/Dialog that changes the data my cursor is tracking. Even in the simplest case, does that mean that I have to manually update my previous screen (a listener for a dialog in the main activity), or alternatively that I have to register a ContentObserver, since I'm no longer updating the data in onResume() (though I could update it twice of course)?
I know it's a basic question but the dialog only recently, to my surprise, made me realize this.
Again the solution depends on what suits you.
If you want the cursor to be pre-populated once per application (and not bothered about any change, then you can do it in onCreate(). This method will be recalled only if the app process is killed and app is reinitiated.
If you want the cursor to be prepopulated everytime the visible lifetime starts (most cases a service/broadcast is calling your activity, you should use onStart()
If you want the cursor to be prepopulated for every foreground lifecyle of activity, you should use onResume(). So if you have a dialog box or another subactivity modifying some information and hence you want to reload the cursor, it is best you do so in onResume(). The downside for this method is everytime the activity comes in foreground the cursor is reloaded.
Hope this makes it clear
To answer your question about NoteEditor, simply take a look at the lines above the one you cite and you'll see...
// Requery in case something changed while paused (such as the title)
mCursor.requery();
The comment seems to explain it all. Although I haven't gone through the NotePad example myself, it appears the author(s) are building in the ability to recover from changes whilst the NoteEditor is paused (and then resumed).
As GSree explains (whilst I was typing this), there isn't a right or wrong answer and it simply depends on what needs to be done at which point of the Activity life-cycle.

Categories

Resources