Hi, today we will talk about one of the basal things in Android application an Activity.
How to understand an Activity
Activity is the basis of your application and entry point as well.
From the user side, it's a single focused thing that user can do while interacting with your application. Most of the Activities interact with the user and take care of creating a window for your UI.
Also, using multiple Activities to represent various tasks helps a programmer to make app's code less complex and easier to maintain.
Activities can be used as fullscreen or floating windows and as a part of another activity (in an ActivityGroup, note that it's deprecated since API 13).
Activity insights
Firs of all to start an activity you should define it in your manifest using <activity> tag inside <application>. Like this:
<manifest> <application> <activity android:name=".MyActivity" /> </application> </manifest >
Every class that extends Activity should implement these two methods
- onCreate(Bundle) - which is an entry point of your Activity, where you should initialize it (or recreate it we will talk about it later). You can think about it as a kind of constructor for your class. Usually, here we set an activity layout using setContentView(int) and set all the necessary fields including ones that relate to our layout using findViewById(int).
- onPause() - this one is called when the user leaves your Activity. At this point, you can save all data that can be necessary for future Activity launches (usually using ContentProvider which I will talk about in future posts).
There are many more events in Activity lifecycle, let's look at these.
Activity lifecycle
A set of activities is managed as a stack it means that when a new activity is started it is placed in the top of the stack and remains there until it destroyed or another activity is started. On the other hand, previous activities are below the new one in the stack and remains there while all the upper activities exist.
While in the stack, an activity can be in one of the four states.
- Activity is running (at the top). While in this state activity performs all the actions.
- Activity is not in focus but visible, or paused. It means that there's another activity that is semi-transparent or doesn't take all window's space so OS still should maintain UI of background activity. In this state, activity is still alive and can perform actions, but it's not recommended because it can be killed in the case of extremely low memory, while in this state. This is why we save all the data in onPause().
- Activity is not visible, or stopped. In this case, activity is still alive and still holds the state and member information, but there is more probability that it will be killed to free memory for something else.
- Activity is dropped, as I said OS can drop activity if it needs to free memory for something that has more priority. It does it by asking activity to finish, or simply killing its process (it's one of the reasons why you should save data before paused state). When the user decides to go back to this activity it's completely recreated, the developer should consider it and restore it to the previous state.
Here's a diagram from Activity documentation that shows most important parts (colored) of an activity lifecycle and all the methods that are called during this lifecycle.
As you may see, activity exist even if app process killed it's just remaining in the activity stack and waits until the user navigates to it again, in this case, it should be recreated, using saved data. When activity is finished or system should completely destroy it, onDestroy() method is called and OS shutting it down.
In the onDestroy() method activity app should release all the remaining resources (close all the connections, shut down all the threads related to it etc.)
Why lifecycle is so important
As I said, the system can decide to kill your activity if there's some higher priority process that requires memory. In this case, you should save your activity state in order to recreate it, when user will navigate to it again.
But this is not the only case when you should recreate an activity. Another reason to recreate it is configuration change.
Such things as orientation change, language change, or input devices plugging (like a keyboard) will cause your activity to go through its' lifecycle straight up to onDestroy() and after that system creates a new instance of your activity and calls onStart(Bundle) on it with savedInstanceBundle that contains the state of previous activity.
The reason to do so is quite simple. The fact is that in different configurations you app can use different resources, for example, you may want your app to look different in portrait and landscape orientations because in landscape you have more horizontal space.
However, you may want your app to not be recreated after some configuration changes. For example, if you don't care about whether a keyboard is plugged in or not (or you want to handle it yourself).
In this case, you can tell the system to just warn your activity about a configuration change instead of killing it.
To do so you should use android:configChanges attribute in activity's manifest to specify those changes. After that whenever specified configuration is changed onConfigurationChange(Configuration) will be called on your activity, and you can handle it yourself.
Also, activity's lifecycle in many ways controls lifecycles of all it's fragments (I will write about these in future posts).
Ways to save the state of an activity
I hope that when you have read the above, you have that one question. How to save the state of my activity? So if you do, read on.
There are two ways to do so. And these two ways should be used in different cases.
Case #1: You need to save some underlying information. Consider your user made some changes in his profile in this situation when the user leaves edit activity you should save all the applied changes to the database. Doing so you kill two birds with one stone. You update your database with new information and save the current state of your activity and when the user comes back to it the app will read it from the database.
As was said it's preferable to do in onPause(). It looks something like this.
@Override protected void onPause() { super.onPause(); //Always call the superclass method first, it performs operations required by system //Save applied changes to the database } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Read from database and populate the views }
Case #2: You need to save the state of your UI. Let's refer to our example with edit activity. The user can start typing something in EditText and leave you application because of an important message or something, and when he returns he wants everything in text fields to be as he left it. To achieve this effect you should use onSaveInstanceState(Bundle) and populate the bundle with the data you need to save.
Actually, SDK already takes care of it but if it didn't you would write something like this
@Override public void onSaveInstanceState(Bundle outState) { outState.putString(EDIT_TEXT_STATE, mEdit.getText().toString()); super.onSaveInstanceState(outState); //Call superclass method as well. As I said, it handles states of some elements for you. } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Always call the superclass first // Check if there is a state Bundle if (savedInstanceState != null) { mEdit.setText(savedInstanceState.getString(EDIT_TEXT_STATE)); } }
Summary
It's pretty much all the basics of activities. With it, you can build activities that don't care if system kills them, they will stay in the state that they were left. For complete reference about activities visit the documentation page and the guide. Here you can learn about intent-handling and result activities.
See you next week, peace!