Activity being destroyed? - android

Very new to Android but when I am, say, in activity A, and I intend to move to activity B, then go back to activity A, all the data displayed in activity A before going to to B is lost. I never call finish(), am I doing something wrong?

I recommend going through Google's training and learning about activity life cycles.
http://developer.android.com/training/basics/firstapp/index.html
With your two activities, override all of the life cycle methods (onCreate, onResume, etc) and put a simple log message in them. Just move between the activities, and watch your log to learn the order of events.
From there, learn about Bundles and how to save your instance states and you'll be well on your way to making apps!

Check that all your Views do have identifiers in your XML. Android restores only those views which have identifiers.
Additionally, for your custom data (not views):
It can be that your Activity A got destroyed while in background.
Normally they do like that:
1) Add onSaveInstanceState() to your Activity. There put all your custom data in the Bundle argument. Be sure call super at the end. You do not need to store your views, just your custom data such as your custom variables etc.
2) in onCreate see if the savedInstanceState Bundle argument is null.
3) If null populate with your default data.
4) If not null restore the data from the Bundle and populate with them

Related

Android activity/fragment responsibilities for data loading

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.

Android start main activity when another activity is called by broadcast

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.

Is it possible to pass an array of Objects through a bundle?

I have a question similary to this guy, but slightly different. In the original question, he says
Suppose you want to start a new activity and pass it some data from
the current activity.
The first answer talks about putting things in Extras, so presumably he's talking about passing Intents.
However, what if you only wanted to pass between two instances of the same activity? For example, if you rotate the screen, the "old" instance of an activity is destroyed and a "new" one created. The way to pass information between these is through a Bundle. I know how to pass primitive data types with onSaveInstanceState.putXXX and .getXXX. But what if I have an array of Objects? How can I pass these in a Bundle? Are Parcelable and Serializeable my only options?*
*assuming I don't want to use a static variable
Basically we have a couple of options here.
Option 1 is to use Activity.onSaveInstanceState() method. There you store everything into an instance of Bundle class. Bundle requires simple, parcelable or serializable types. You can pass arrays too, but these must be arrays of those types.
Option 2 would be to override Activity.onRetainCustomNonConfigurationInstance() and return your array from there. New instance of this activity can retrieve this array by calling Activity.getLastNonConfigurationInstance(). Although this option works fine, it is already deprecated. This is where 3rd option comes into play.
Option 3 is to use a retained Fragment. Here the idea is to create a Fragment and to call Fragment.setRetaineInstance(true) in either onCreate() or onCreateView() of this fragment. Once called, this fragment becomes "retained". If you rotate your device, then new activity instances will be created with every new rotation, but the same instance of retained fragment will be passed to every new instance of the activity. If you keep your array there, it will be available in every new activity instance instantly. This would be a way to go.
I would like to note, that option 1 is persisted. If your app goes into background and Android kills it and later starts again, you will have your array delivered to onCreate(Bundle savedInstanceState). In contrast to this, options 2 and 3 will lose the state. If you can re-create your array every time activity is created, you can go with option 2 or 3.

Passing pointer to Activity to next Activity

I'm very new to Android programming (and Java for that matter) coming from an iOS background.
What I am trying to do, is pass a pointer to a Fragment from one Activity to another.
Basically, I have a starting activity called BeginActivity that handles a couple of Fragments for login and register screens. Once logged in, I load up the main activity of the app called TabsFragmentActivity using this code:
public void loggedIn() {
Intent intent = new Intent(this, TabsFragmentActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
this.startActivity(intent);
finish();
}
I'm using FLAG_ACTIVITY_CLEAR_TOP as I dont want the user to go back without actually logging out first.
Now the problem:
In BeginActivity I have a pointer to a fragment that holds the users data. I am using it like a singleton, that the first few view fragments can access from BeginActivity.
I need to pass this same object to the new TabsFragmentActivity before I call finish() on it.
How do I do this?
I know I can use putExtra() but I believe that is just for strings etc.. and not other Fragments.
Is there a way in the newly created TabsFragmentActivity that I can reference the BeginActivity to 'grab' the pointer?
Thanks
First of all, you should be sure about Fragments and Activity life cycle.
Fragments are designed to be reusable UI complex components. They look like activity, but you can reuse. So,you can have as many activities you need containing the same fragments, but not the same instances of these fragments.
If you just want to pass you user data for another activity you must use Bundle and putExtra(). Depending of the user data type can be necessary implements Serializable or Parcelable Interfaces, as #gheese said.
If you want to use the same UI appearence of your fragment on two or more activities, besides use Bundle and putExtra. Each activity that you want this behavior must contains a field whose is a Fragment and in the moment of starting this fragment you can use getActivity().getIntent().getExtra to get the user information and populate your fragment.
Basically you need to be able to pass your class via the intent, look at Serializable / Parcelable interfaces
This question has the answer you require
How to pass an object from one activity to another on Android

onPause / onRestore with savedInstanceState

I'm pretty new to android development and I need some help saving the state of an activity.
What is the correct way to save the instance from onPause and restoring it from onRestore since obviously Android isn't sending the savedInstanceState Bundle as it does with onCreate or onSaveInstanceState for example. Or is there a better way to save other than using the savedInstanceState bundle?
Does this make sense?
[edit]
Ok, i think i know what my real problem is... But first, I think what I was looking for was to use SharedPreferences instead of savedInstanceState.
So, doing more debug log watching I'm noticing that instead of bringing the Activity to the top of the stack it's creating a new one. Yes, I realize I'm creating a new one....
Intent itemintent = new Intent(MediaList.this, AudioPlayer.class);
Bundle b = new Bundle();
//...putString some strings to send
itemintent.putExtra("android.intent.extra.INTENT", b);
itemintent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityForResult(itemintent,0);
...But isn't FLAG_ACTIVITY_REORDER_TO_FRONT supposed to stop it from creating a new activity? I'm guessing it thinks it has to create a new one since i'm sending along some strings?
Better yet, how can I check if the activity is already in the stack and switch to it as long as the strings are the same? -- I'm starting this activity when the user clicks a media item from a listview.
[/edit]
For some reason this is not documented in very very bold neon flashing letters, and took me a while to discover, but you don't need to worry about whether your activity exists or not if you simply create it with the
android:launchMode=["multiple" | "singleTop" |
"singleTask" | "singleInstance"]
property set to "singleInstance".
Then there is only ever one instance of it, and your memory fields are preserved as long as the activity hasn't been garbage collected.
The other thing you can do is to create an Application (extended from Application) and store all your persistent objects up in that... it is created first and destroyed last as far as your entire app's life cycle is concerned (including all your activity-less services).
Just create an Application class and specify it in your manifest like this:
<application android:icon="#drawable/icon" android:label="#string/app_name"
android:name=".MyApplication">
Then if you still REALLY want to save your values for situations where the app is going to be closed, just use SharedPreferences.
What is this onRestore method you speak of? It is not part of the Activity lifecycle... I will suppose you mean onRestart. Anyway, the reason you don't get a bundle for onRestart is because you don't need one. Your activity hasn't been officially "killed" so you don't need to restore from a saved state. Your activity was paused, but not removed from memory, so the system is just telling you that it was made visible again. You probably don't need to do anything for this sort of transition event.
Other than that, the way to do it is to save anything you consider a "state" value in the onSaveInstanceState(), then restore them in onCreate. After that you can restore any view-specific properties either on the onCreate itself, or later in the Activity lifecycle (e.g. onResume).

Categories

Resources