In my Android application there are many instances where multiple activities call a common service passing it a callback
Now if the activity is destroyed and recreated (say due to orientation change) then there is every chance that the callback reference is lost.
I know the normal ways of using onsavedinstance method or an headless fragment of persisting.
But in that Way all my activities have to handle it. Is there any common way to handle this.
Note : I just want to have a simple and reusable code for the persistence to happen
I just want to have a simple and reusable code for the persistence to happen
You can create an activity class where you would write all the state management boilerplate code and then make other activities inherit from this base activity.
Related
I am somewhat new to Android, and I am writing an app. I am getting to the point where I am starting to more thoroughly test my code, and therefore, I would like to implement the MVP design strategy since it adds more testable layers to the code. One of the supposed benefits of using MVP that I can not seem to understand is how it helps with running AsyncTasks as they are performed dynamically. Since you want to avoid any Android specific components in your Presenter class, how are you supposed to reference the Activity that utilizes the AsyncTasks? Tutorials about MVP show the Presenter object having methods that take in an Activity as a parameter and return to it; however, if your AsyncTask takes a long time and your Activity has been destroyed through something such as rotation change, how do you return to the proper Activity? I currently store my AsyncTask in a Fragment so that it is saved on Orientation Change. I am having a hard time finding a workaround that implements the MVP practice.
To answer your question, there isn't much you can do to avoid passing Android classes to your Presenter class. But instead of passing the Android object as a parameter, add a method to your View class that returns it (e.g. getActivity()).
That said, I strongly suggest you use a Loader instead of an AsyncTask. Loaders were designed specifically for your use-case. They can also run in the background but their lifecycle is tied to the lifecycle of an Activity or Fragment.
If you switch to Loaders, add a method like getLoaderManager() to your View interface.
If I dont miss-understand your question, your are trying to use retained non-UI fragment for long-runing task, right?
Here is my suggestions in your case:
Make ActivityView interface for your Activity
Using WeakReference<ActivityView> to refer your activity inside your Fragment Presenter (to avoid memory leak issue)
When Activity re-created, try to get your retained fragment and reset your Fragment Presenter's ActivityView. You can look at this Google Example to know how to deal with loading data while configuration changed.
In conclusion, just use WeakReference to avoid memory leak issue, and try to re-set your Presenter'sview when activity is recreated
When starting a new application for a client, I am asking myself again the same question about who should be responsible for loading data: activities or fragments. I have taken both options for various apps and I was wondering which pattern is best according to you in terms of:
limiting the code complexity.
handling edge cases (like screen rotation, screen going power save, loss of connectivity, etc.)
Option 1 - Activity loads data & fragment only displays it
This allows to have fragments that are just fed a bunch of objects to display. They know nothing about loading data and how we load that.
On the other side, the activity loads data using whichever method is required (for instance initially the latest 50 entries and on a search, loads the search result). It then passes it to the fragment which displays it. Method to load the data could be anything (from service, from DB, ... fragments only know about POJOs)
It's kind of a MVC architecture where the activity is the controller and fragments are the view.
Option 2 - Activity arranges fragments & fragments are responsible to fetch the data
In this pattern, fragments are autonomous pieces of application. They know how to load the data they are displaying and how to show it to the user.
Activities are simply a way to arrange fragments on screen and to coordinate transitions between application activities.
In theory you can do whatever you want, if it works.
Actually, the fragments and activities display data and deal with their own life cycles.
Since fragments belongs to activity so you have to use both in conjunction to better handle all the data but mostly it depends on your needs.
If you keep in mind the idea that the Fragment should provide the UI and the Activity should provide the processing then you have a good division of concerns and code which should allow the Fragment or the Activity to be reused.
If you know about the MVC - Model View Controller - design pattern then you can think of the Fragment as the View and the Activity as the Model.
Things get much more interesting when you build an application with multiple Fragments.
Some key points as a decide factor -
The idea of a Fragment is that it is a wrapped up chunk of UI that
can be used by any Activity that needs it. On this basis you have to
ask yourself if the event that has to be handled is the same for
every Activity or unique to each Activity. If it is the same then the
event handler is better written within the Fragment.
The Fragment doesn't have a UI of its own - it is displayed by an
Activity that the Fragment is associated with. The events are
generated by objects in the View hierarchy, which is owned by the
Activity. If you try to use Android Studio to add an event handler,
for example, it will add it to the Activity and not to the Fragment.
You can define the EventListener that you want to handle the event
in the Fragment and then hook it up to the View object in the
Activity in which you want to generate the event.
A Fragment is a class that implements the onCreateView method to
supply a View hierarchy that can be displayed by an Activity.
To use a Fragment in an Activity you have to add it using a
FragmentManager and a FragmentTransaction. You can add the Fragment
using the add method but nothing happens until you call the commit
method.
After the method that used the commit, usually the Activity's
onCreate, terminates the CreateView event runs the Fragment's
onCreateView and the Fragments View hierarchy is added to the
Activity's content.
You have to write code to save and restore any additional state the
Fragment may have.
If a task is common to all instances of the Fragment then its code
should live in the Fragment.
In particular the code to handle events can be defined within the
Fragment.
The Activity should be used to host code that processes the data
provided by the UI.
Attaching Activity event handlers to the Fragment's UI or is
difficult to do correctly.
From scenarios make decision what your app will be. Is it service,
activity, widget , even a content provider or a complex system,
including some different components. Test your decision against
scenarios.
All of these have to work after the Fragment has been destroyed and
recreated.
(1) Initialization of the Fragment, (2) Saving and restoring the Fragment's
state and (3) Implementing something like an event mechanism so the Fragment
can get the Activity's attention
The hardest part is implementing something like an event mechanism.
In the case of the complex system, distribute functionalities and
data entities among application components. Make a list of components
and what they are (activities or smth else).
Make the list of UI components with description what they do (not HOW
yet) These will be widgets and activities or fragments or layouts
later.
Often you will want one Fragment to communicate with another, for example
to change the content based on a user event. All Fragment-to-Fragment
communication is done through the associated Activity. Two Fragments
should never communicate directly.
When your app is perfectly modular, fragments don't know about each
other. You can add a fragment, remove a fragment, replace a fragment,
and they should all work fine, because they are all independent, and
the activity has full control over the configuration.
You can't do anything with a Fragment unless you start a transaction.
Within the transaction you can set up what you want to happen,
usually add the Fragment to the current layout, but nothing happens
until you use the commit method.
Efficient handling of data with Screen Orientation -
When screen orientation changes, Android restarts the running Activity (onDestroy() is called, followed by onCreate()).
To properly handle a restart, it is important that your activity restores its previous state through the normal Activity lifecycle, in which Android calls onSaveInstanceState() before it destroys your activity so that you can save data about the application state. You can then restore the state during onCreate() or onRestoreInstanceState().
However, you might encounter a situation in which restarting your application and restoring significant amounts of data can be costly and create a poor user experience. In such a situation, you have two other options:
1) Retain an object during a configuration change
Allow your activity to restart when a configuration changes, but carry a stateful Object to the new instance of your activity.
2) Handle the configuration change yourself
Prevent the system from restarting your activity during certain configuration changes, but receive a callback when the configurations do change, so that you can manually update your activity as necessary.
What I would do is manage all data flow (bluetooth, database storage, etc)
in the Activity and use Fragments only for UI display or handling user input.
This way is easier to handle configuration changes/ screen rotations.
Also, if data flow things are heavy to be on UI thread, consider using a Service with a background thread.
If it is a "one shot" thing, you can use an IntentService,
otherwise you can implement a Bind Service and request a bind from anywhere you have Context.
For more read - fragment-and-activity-working-together.
Ideally neither Activity nor Fragment with UI should contain any "model" logic - these classes should be lightweight and responsible only for UI logic. But when you decide to make a separate model object you have a dilemma to choose where to initialise and store this object and how to deal with configuration changes. And here comes some handy trick:
You can create a model Fragment without UI, make it retain instance to deal with configuration changes (it's AFAIK the simplest way to save data across config. changes without troubles) and retrieve it anywhere you need via findFragmentById(). You make all expensive operations inside it once (using background thread, of course), store your data and you're done.
For more info, see Adding a fragment without a UI section.
UPD: There's now a better way to deal with configuration changes: ViewModel from Google's Architecture Components. Here's a good example.
I prefer and always implemented Option-2 over Option-1.
Reasons for not selecting Option-1:
We should have listeners for events triggered in Fragments and pass it back to activity to load data, process it and push it back to fragment, which makes work more complex.
An Activty can load any number of Fragments, Typically you end up questioning these questions to yourself in a scenario where your app is highly scalable and is already huge. Writing all the events in an activity and passing it over to fragment will be an complex altogether.
As #Ved Prakash mentioned, Handling screen orientation becomes complex if orientation is handled by Activty.
I have an example:
your application have 2 features A and B. the 2 features are independent each other. and each feature has a lot of screen.
you should create 2 activities A and B because when Activity A is used, Activity B should be released to reduce memory of app. And the same when B is used, A should be released. The memory of Context A and B are independent, if you want to send data from Activity A to B you must use intent or use global variable in Application Context. intent is managed by OS, not by application. When A send intent to B, if A is destroy is no problem with intent send to B. Activity is App module, it is can call by other applications (fragment is impossible).
for example: feature A has a lot of screen (ex: Fragment1, Fragment2). they use the same data and depend on each other. each screen should be a fragment. and when process with data you can get reference to data by calling function getActivity() and then get reference to variable of Activity context (or Activity memory) to write or read it. Fragment1 and Fragment2 are belong to Activity A Context.it means that Fragment 1 and Fragment 2 can transfer data with each other via variable of Activity context, it is easy to do . noticed that Intent is managed by OS,it is so expensive when send data via Intent.
I am having an architectural problem with an Android project. I have the main activity(A) where a lot of stuff is initialized then I have 1 Activity(B) that handles some broadcasts from the system, this activity needs to access the stuff initialized by the main activity. If the app is killed and the activity (B) is called the onCreate of the Activity (A) is not called so the stuff is not initialized, how can I handle this situation properly?
That's a sign of not properly encapsulating the logic.
I don't know what your app is about, so that makes it difficult to generalize, but probably your Activity A has a lot of objects and variables related to you model, what you should do is isolate all this logic of your model in a single component, that you can initialize with a single call (or a few lines) either from activity A or B.
This logic can include opening files or sharedPreference, initializing objects, downloading data... Ideally all the logic is isolated from the user interface. The User Interface, on the other hand should be only responsible to present the data in a human readable (and hopefully enjoyable) way.
When first time your activity B is called, pass all initialization values to it from Activity A and save the in Activity B.
If app is killed and activity B is called, it have all the initialized values.
You should develop App using MVC arthitucture
Check this MVC Pattern in Android Development
This will help you batter.
I am new to Android development. After learning from many tutorials I got many Activities and many Fragments. How can I make a core engine to check what Activity is running and what Fragment is showing on a container?
Assume that I have:
Acivity01, Activity02, ... , Activity10
Fragment01, Fragment02, ... , Fragment10
I want to make a class that filters the Activity where Activity is on runtime and what Fragment is embeded to that activity.
How can I do this?
If I understand you correctly, you may want to store some references within your Application class to an Activity and to Fragment instance(-s), which are currently in foreground (by this I mean that user can instantly interact with Activity/Fragment).
As for Activity
Create some Activity field in your Application class and getter/setter methods for it (e.g., setCurrentActivity(), getCurrentActivity()). Then call setCurrentActivity() from onResume() method for each of your Activity instances. Don't forget to call setCurrentActivity, supplying null reference to ir in order to properly handle a case, when there are no foreground activities, but application is stll working.
As for Fragment
The general idea is similar to the first item, but there can be more than one Fragment instance in foreground state at time. So you need to store something like List, where you add your resumed fragments and remove paused.
You may also want to implement something similar for dialogs, for example. Then use the same strategy. Hope it will help.
I have a similar issue with this one:
Android: Multiple activity instances launched by same intent. Bring one uniquely to foreground?
I need to create a stack of activities, all created by using the same class: it is a class defining a news list, only there needs to be multiple children activities that are also news lists, but from different categories. (I do need to have these activities in a stack)
The trouble is I need to change data on each of these activities after they are shown, but I can't find a way to access each one of these activities separately, since they are all using the same class, so if I used static methods, I would change the data on all these activities at the same time. Ideally, there could be a way to use references of each activity, so that I can access methods on each one separately, but I don't think there is a way of doing this.
I might as well pass parameter IDs when starting each activity, and instantiate objects at the same time, for each activity, and using these IDs later access the respective objects' methods...
Edit to clarify: Let me use an example to what I am trying to achieve. I have an A class and I am using this same class to instantiate multiple activities, in a stack. After the creation of these activities, I need to alter data, say, on one of these activities statically, so by calling A.alterData(); , but not when the activities are created, so there is no way of doing this by starting the activities with different data.. Since there are multiple instances of this class, if I do so, this will result on altering the data on all these activities, that are using the A class. Would I be able to somehow use objects and methods to these objects to alter data on different activities that are using the same class?
any other ideas?
You could use an ActivityGroup. It basically holds a list of activities and you need to control the navigation around them. It sounds like it suits your situation. There are many examples of them that can be found through google.
How I would approach changing the data on the other screens is by using shared preferences. You can store whatever data you need in there, and then (through your activity group) when you change screen, the data is refreshed. This is faster and a little more efficient than restarting the intent every time.
Another way is to change the data in the background without the user noticing. This can be done because an Activity group loads all of the Activity it holds and they are always there in the background, running, unless the developer states otherwise.
You could grab a a hold of the appropriate instance of the class you want to change the data on and then just change it.
Does any of this make sense?
I can elaborate more if needed.
I would supply the parameters to each activity, such as:
intent.putExtra("category", categoryId);
That way you aren't managing too much global state.
About changing the data - if you are talking about refreshing the data from its original source, then you should probably be doing this in the onResume() method of the Activity. Check out the Activity Lifecycle.
This has a few benefits:
you will have access to all of the context of that Activity
you won't have to do something nasty like access another Activity's data
you won't waste time refreshing data the user isn't looking at
Even if you have to make updates to the data, there are ways to make sure each Activity "minds its own business".