Android: Lifecycle

The following diagram is helpful in understanding the Android Activity Lifecycle. This diagram is from a google code lab which can be found here.

onCreate(): This is only called once, before the activity is visible. Handle any one-time initializations such as inflate the layout, define click listeners, initialize variables, or set up view binding. The Bundle parameter will be null the first time an activity is started, but if it’s been destroyed and recreated, the Bundle will contain any info that was saved in onSaveInstanceState().

onRestart(): This is not called when the activity first starts, but only after being restarted after having been previously stopped, such as when a user has gone back to the home screen, then reopens the Activity from the recents screen. This is where you can put code you want to call only if your app is not being started for the first time.

onStart(): This can be called many times and the activity is visible after onStart() runs. It gets called when the Activity returns to the foreground such as when screen is turned back on or when returning to the activity from the home screen or another activity.

onRestoreInstanceState(): You can restore data that was save in onSaveInstanceState(), though generally it is better to restore it in onCreate(). Restore it here in case it needs to be stored after onCreate(). The same Bundle is passed to both methods.

onResume(): This is always called after onStart() even if the activity is just starting and there is nothing to resume. This is where the app gains focus and the user can interact with it. When the activity has been paused, onResume() will be called when it regains focus.

onPause(): This is called when an Activity no longer has focus but is still visible on the screen. For example, when a user chooses to “share”, a dialog pops up which then has focus, but the Activity can still be seen behind the dialog. Code that runs in this method can block other things from displaying, so it should be kept light weight.

onStop(): This is called when an activity moves into the background, such as when a user returns to the home screen. After onStop() is called, the Activity is no longer visible on the screen, but it is still in memory in the background and resources are still in use.

onSaveInstanceState(): This is where you save any data you might need in case the activity is destroyed. It is called after onStop() even if onDestroy() is not called. Any data saved to the Bundle can be restored either in onCreate() or in onRestoreInstanceState().

onDestroy(): This is called once to clean up any resources used by the activity when it is shut down. Once an activity is destroyed, an Activity can be garbage collected. Activities can be destroyed by rotating the device, hitting the back button, by calling Activity.finish(), or when a user force-quits the app. Activities that have not been used for a long time may also be destroyed. First, it will be paused and stopped.

Fragment Lifecycle

Fragments have their own lifecycle depicted in the diagram below. You can learn more about the Fragment Lifecycle and see the original diagram in this codelab.

You can access the 5 Fragment states in the Lifecycle.State enum:

INITIALIZED: A new instance has been instantiated.
CREATED: The fragment lifecycle methods are called. The view associated with the fragment is created.
STARTED: The fragment is visible on screen but does not have focus.
RESUMED: The fragment is visible and has focus.
DESTROYED: The fragment has been de-instantiated.

Override the following methods in Fragment to respond to lifecycle events:

onCreate(): The fragment has entered the CREATED state. It has been instantiated but there is no view yet.

onCreateView(): This is where you inflate the layout (note this is different than Activity).

onViewCreated(): This is called after the view is created and is when you would bind views to properties (with findViewById()).

onStart(): The fragment has entered the STARTED state,

onResume(): The fragment has entered the RESUMED state. It has focus and can respond to user input.

onPause(): The fragment has re-entered the STARTED state and is visible.

onStop(): The fragment has re-entered the CREATED state. It is still instantiated but is not present on screen.

onDestroyView(): The view has been removed from memory but the fragment object still exists.

onDestroy(): The fragment has entered the DESTROYED state.

Android: Intents (Kotlin)

There are two types of intents: Explicit and Implicit. The following examples and info come from this codelab.

Explicit intents are generally used to start another activity within your app. You can construct it with the constructor that takes the Context and the Activity class as parameters. Use Intent.putExtra to send parameters to the new activity. For example:

val intent = Intent(context, DetailActivity::class.java)
intent.putExtra(DetailActivity.LETTER, item.toString())
context.startActivity(intent)

Implicit intents are generally used to start an activity of the user’s choosing. For example you may have several browsers on your device that could be used to open a URL. You can construct it with the constructor that takes the Intent type and the Uri. For example:

val query = Uri.parse(DetailActivity.SEARCH_PREFIX + item)
val intent = Intent(Intent.ACTION_VIEW, query)
context.startActivity(intent)

Android: RecyclerView (Kotlin)

XML Layout
Create a new layout file with a LinearLayout at the top level if you plan to display multiple Views for each item. If you will only have one view, i.e. a TextView, you can make that your top level View instead. Give it an id and set the layout_width and layout_height to “wrap_content”.

Adapter
MyAdapter extends RecyclerView.Adapter<MyViewHolder>
Once you have created the Adapter class, go ahead and create the inner ViewHolder class so the implemented methods will have the correct type. Then implement the Adapter classes:
onCreateViewHolder – Inflate the xml layout, and use it to create and return an instance of your ViewHolder.

val adapterLayout = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)

onBindViewHolder – Get the item from the cached list of items, and use it to set the content of the View inside the ViewHolder (be sure to handle a null list of items).
getItemCount – Return the size of the cached list of items – handle null case.

ViewHolder
MyViewHolder extends RecyclerView.ViewHolder. This can be an inner class of the Adapter. The constructor takes a View as a parameter. This is the layout that gets inflated by the adapter. Get any Views from the parent and store them as a member variables. You can call findViewById on the parent View to get its children.

MainActivity
onCreate – Set up the RecyclerView

// Kotlin
// Initialize data.
val myDataset = Datasource().loadAffirmations()
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.adapter = ItemAdapter(this, myDataset)

// Java
RecyclerView recyclerView = findViewById(R.id.recyclerview);
recyclerView.setAdapter(new MyAdapter(this));
// a layout manager must be provided for the RecyclerView to function
recyclerView.setLayoutManager(new LinearLayoutManager(this));

Android: View Binding

In your app build.gradle file, add the following lines to the “android” section:

buildFeatures {
    viewBinding = true
}

In your main class, create a member variable called, “binding”, where the name of the binding class is the name of the layout converted to camelCase:

 lateinit var binding: ActivityMainBinding

In onCreate(), initialize the view binding:

binding = ActivityMainBinding.inflate(layoutInflater)

Call setContentView with “binding.root” instead of the main layout file:

setContentView(binding.root)

Now you can access views using the binding object like this, where the name of the view is its id converted to camelCase.:

binding.myViewId