I'm working on an app, which needs to do a lots of calculations in the background.
To do this I start a thread from a fragment and pass a Handler to it, so it can pass messages back. When a configuration change occurs (screen rotation, ...) Android recreates the Activity and Fragment. I'm looking for a way to get a reference to the thread from the new Fragment, so I can pass a new Handler to it.
Retaining the whole Fragment is not an option for me, as it uses a different layout in landscape mode.
I can't use onRetainNonConfigurationInstance(), as that is only supported on Activities, but my thread lives in a fragment.
I can't use onSaveInstanceState(), as that only supports primitive data types.
Are there any other ways for me to retain a reference to my background thread when the fragment is recreated?
I solved the problem using a headless retained fragment, which manages the thread.
My normal fragment creates a new instance of the headless fragment, which is retained. The headless fragment has start() and stop() methods, which in turn start and stop the thread and a setHandler() method, which changes the handler messages are passed to.
Whenever the non retained fragment is recreated it just has to get the retained fragment from the FragmentManager and call setHandler() with a new Handler.
You can use the ViewModel of android architecture components to do this.
Lifecycle aware components: https://developer.android.com/topic/libraries/architecture/lifecycle
Google's ViewModel: https://developer.android.com/topic/libraries/architecture/viewmodel
Related
I am new in Android so correct me if i am wrong. When another activity is opened, the first one is destroyed. So i have to pass all variables to the new activty if i don't want to lose the data. Or, can I run another not UI thread that manages my data?
Basically I need to change layout in my app on button click. Is there any way to do it within the same activity or i have to start another activity with the new layout?
You can use one activity in your app and do what you want in fragments. Navigation is good tool to use for relating fragments to each other.
well initially you can use a single activity and in that activity you can call multiple fragments as per your need,
and for the data you can use MVVM architecture with room architecture, it saves your lots of time and code.
and go with navigation graph if you want a quick and easy implementation.
you can start all this with this demo.
As google suggests single activity based application. I have a situation where I need clarification.
I have one activity containing 3 fragments and each fragment is linked to different fragments having other screens.
should I use only one viewmodel for each tabs or should I use one view model having different screens.
As I have only one activity and view Model resides till activity is destroyed. Do all viewModel that I will create for each screen will contain data until activity is destroyed. If this is the case will it make my app heavy.
should I use only one viewmodel for each tabs or should I use one view model having different screens.
You should use the smallest scope for each ViewModel possible. Generally, this means that data associated with only one fragment should use a ViewModel associated with just that one fragment.
As I have only one activity and view Model resides till activity is destroyed. Do all viewModel that I will create for each screen will contain data until activity is destroyed. If this is the case will it make my app heavy.
ViewModels live only as long as the ViewModelStore they're attached to is around. Therefore if you have a ViewModel associated with a fragment, it'll survive only as long as that fragment exists. For example, if that fragment gets popped off the back or you call remove(), then the ViewModel is destroyed. ViewModels only live as long as your activity if you specifically create them using the activity as the ViewModelStoreOwner (for example, by using ViewModelProvider(activity)).
should I use only one viewmodel for each tabs or should I use one view
model having different screens?
In single activity architecture, you can use ViewModel with either Activity Scope or with Fragment scope. As #ianhanniballake suggested in his answer, use ViewModel with Fragment which means that each tab in your case will have its own ViewModel attached to fragment. This will provide separation of concerns for functionality in each tab.
As I have only one activity and view Model resides till activity is
destroyed. Do all viewModel that I will create for each screen will
contain data until activity is destroyed. If this is the case will it
make my app heavy.
Again answer to this question is connected to your first question and explanation provided to it.
While working with single activity architecture narrow down scope as much as possible. Use ViewModel associated with activity (lets call it Global ViewModel) only to keep data which is used across multiple fragments. This way viewmodel will contain data till activity is in backstack and fragments can use it when required.
This will provide you 2 advantages
ViewModel will not contain additional data which you mentioned in your 2nd question
And most importantly there will not be any data discrepancies while accessing fragment multiple times. For e.g. if you open any fragment, fetch data from api and keep it in Global ViewModel and fail to delete it when remove fragment from backstack then your fragment will show old/obsolete data when you will open fragment next time. To avoid this scenario it is better to keep this data in viewmodel with fragment scope.
I hope this will be useful.
Each Fragment usually should have a ViewModel itself but in some cases where you want to share the same ViewModel instance, you can achieve it with having a ViewModel scoped to an activity.
ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel it is found on the docs and you might have to read other details there but technically you can scope a ViewModel to a Fragment or to an Activity.
I have a fragment an onCreateView I do a background asyn call to fetch some data to display.
I save the object that is the result of the background call as a member variable of the fragment.
When I see the UI and the data all is ok and when I press the home button the app goes to background. When I reopen the app the data are in the UI inflated by my fragment.
So now I am not sure about the following:
1) Should I save my object in the onSaveInstanceState?
2) Where should I expect to restore it? In the bundle passed in the onCreateView?
3) When would the data be saved in my bundle? I mean how can I see that without saving it right now, I would lose the data from my UI?
In your fragment constructor, add the following line:
setRetainInstance(true);
Control whether a fragment instance is retained across Activity
re-creation (such as from a configuration change).
Also like an activity, you can retain the state of a fragment using a
Bundle, in case the activity's process is killed and you need to
restore the fragment state when the activity is recreated. You can
save the state during the fragment's onSaveInstanceState() callback
and restore it during either onCreate(), onCreateView(), or
onActivityCreated(). For more information about saving state, see the
Activities document.
It seems that your fragment works alright by fetching the data every time it's shown.
If you want to save its data to avoid the async fetching you can use onSaveInstanceState, which requires you to save your data using a Bundle.
Then in onCreateView check if savedInstanceState is null and if it is do the async fetch, otherwise recreate you data from the savedInstanceState Bundle.
It depends on your data (size).
Do you want to have a fragment on the back stack (with retained fragment you cannot)?
For "home button action" and non-retained Fragment implement Parcelable interface and use onSaveInstanceState() to save and onCreateView()/onCreate() to restore data from a Bundle.
Be aware for back button you will loose your data.
I'm a total beginner with Android and Eclipse and I have few questions that will help me understand the philosophy of Android:
The activity does all the work "behind the scenes". Activities are connected to a layout in the XML file. When the activity is started, if declared in setContentView method, the connected layout will be shown. Activity can be independent, without any layout, it can be invoked by another activity and will do all the work without showing any layout.
Activity is something like a php file which is invoked by my submit button in HTML, and the layout is .HTML which shows elements.
Am I right with this one?
For example, if I want to change the layout of my app, I want to show Layout2.xml when clicking button in Layout1.xml. Then I have to destroy the activity which is connected with Layout1.xml and start the activity which is connected with Layout2.xml? Is this correct? Is there any better way to do this?
How can I (by which method) destroy/stop a certain activity?
Thank you in an advance.
The best bet is to read the Android documentation regarding activites at http://developer.android.com/reference/android/app/Activity.html
I will answer your specific questions here though
An Activity is a window that the user can see (or a hidden window if there is no layout defined). It deals with the logic of a part of the app that the user can see and interact with. If we take the MVC model (Model View Controller), the Activity is the controller, in terms of it controls which data from the Model is shown on the View (the xml layout).
If you want to show a new window/screen/activity you do not need to destroy the current one. You can open a new activity whilst keeping the old one in the background (in the back stack). With the use of fragments, you can have multiple fragments in an activity so rather than changing activities, you can change fragments in a single activity. For more information about fragments take a look at http://developer.android.com/reference/android/app/Fragment.html.
This point relies heavily on the activity lifecycle. When an activity is destroyed, it means it is finishing and this can be done by the user pressing the back button whilst on the activity, the activity calling finish() on itself or by the Android operating system destroying the activity because memory is required elsewhere (this can happen when the app is in the background).
When we say an activity is stopped, it means that the activity is no longer visible to the user. This can be the case where the activity is in the back stack (another activity is in front of it) or if the app has been put into the background.
This is a brief answer to your questions but I highly recommend you read the Android documentation to gain better knowledge.
I read quite some articles about fragments, but I am still confused about how to do what.
I have a MainActivity, which displays two fragments side by side. In one of the fragments I have a button and defined in the fragments layout XML for the button
android:onClick="buttonClicked"
Now I want to implement that method
public void buttonClicked(View view)
I would have assumed that this has to be implemented in FragmentA.java and not in MainActivity.java. But it only works if that method is implemented in MainActivity.java. Why is that? To me that doesn't make sense. Pre Honeycomb a method belonging to one activity stayed in that activity, now on a tablet I am merging many activities to one MainActivity and all the different methods are merged? Whatever do you put for example in FragmentA.java then? What if you have to start you an own activity because this app runs on a handheld, then the onClick method has not to be in the MainActivity but in the Activity which needs to be called then. I am pretty confused at the moment...
I'm not sure what the specific problem is, but maybe this will help.
From the Android documentation on Fragments:
You should design each fragment as a modular and reusable activity component. That is, because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment.
That is, you should never manipulate a fragment from another fragment; rather, this should be done through the underlying Activity. Read the "Creating event callbacks to the activity" section in this article for more information (it's important stuff!!).
On the other hand, if you want the button to perform an action within the Fragment itself (i.e. if you wanted a Button click to change the text of a TextView within the Fragment), you should implement this in the Fragment, not the Activity (this is because the resulting behavior is contained within the Fragment and has nothing to do with the parent Activity).
Leave a comment and I can clarify if my post is confusing... I only recently began to understand Fragment's myself :).
Well,
I guess it is related to hierarchy of android context structure.
Activity is host of all child views and hence you can say fragment is actually using its host's context.And that's why when you use onClick with fragment system always searches it in Host activity of fragment.
Check it on.
Android developer onClick attribute description
I haven't checked one thing but you could put a test.
By providing implementation in host activity rather than in fragment,but use onClick on layout file of fragment.It should call parent's method.