Android tutorial: starting another activity

Android Development, Tutorials

If you are an Android developer you may encounter a problem with app navigation during the app development process. In this Android tutorial I will describe a solution that makes code management much easier. Keep on reading and find out how to do it.

In the official Android guide, we can read about how to program the display of another view in an application. However, this is a very simplified example that does not work well in complex applications. During my own work, I came up with a rather interesting solution, which greatly simplified code management. Keep on reading “Android tutorial: starting another activity to find out how to do it.

Starting another activity by Android Developers

Let’s assume that in Android application we have created a list of projects from which we can access the details of a selected project. After selecting the element showing the list of projects, we go on to view its details. If we write this navigation in the same way as the guide shows it, it would look like the following example:

const val EXTRA_PROJECT_ID = "com.gratitude.ProjectId"
const val EXTRA_PROJECT_NAME = "com.gratitude.ProjectName"
const val EXTRA_PROJECT_BACKGROUND_IMAGE_URL = "com.gratitude.ProjectBackgroundImageUrl"

class ProjectsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_projects)
    }

   fun showProjectDetails(project: Project) {
        val intent = Intent(this, ProjectDetailsActivity::class.java).apply {
            putExtra(EXTRA_PROJECT_ID, project.id)
            putExtra(EXTRA_PROJECT_NAME, project.name)
            putExtra(
                EXTRA_PROJECT_BACKGROUND_IMAGE_URL,
                project.backgroundImageUrl
            )
        }
        startActivity(intent)
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_project_details)
   
    val id = intent.getStringExtra(EXTRA_PROJECT_ID)
    val name = intent.getStringExtra(EXTRA_PROJECT_NAME)
    val imageUrl = intent.getStringExtra(EXTRA_PROJECT_BACKGROUND_IMAGE_URL)
    
    val projectNameTextView = findViewById(R.id.projectNametextView)
        .apply {
            text = name
        }
}

The guide has done its job. It shows navigation between activities in a way that is accessible to the reader. Problems may appear only after the application has grown.

Android app development: detected problems

Android tutorial

When the application grows, it will be difficult to maintain such code.

To start with, let’s define the main problems:

  1. Patchy data transfer between activities
  2. Incomplete building of intentions and start-up activities
  3. Inconsistent data collection from intentions

How can we improve the above approach?

Let’s ask some questions and try to find an answer to them:

How can you unify data transfer between activities?

  • This problem can be fixed in many ways
  • For each value we need to create a key, thanks to which, we will be able to receive a transferred value. Maintaining these keys is difficult
  • We can save all transmitted values in a model, and add the instance of the model to a bundle of intentions, which will reduce the number of keys to one

How can we unify the method for creating intentions and starting activities?

  • To start a different activity, we need to build an intention, which causes a duplication of code if it is written new every time
  • We can create a function that will build the intention and start the activity

How can we unify the method for receiving data from an intention?

  • This code is often repeated, so you can improve its readability
  • We can create a function that will receive data from an intention

In the following part of the Android tutorial: starting another activity, let’s try to go through some solutions to the difficulties described above.

Android app development: the solutions

Incomplete data transfer between activities, building intentions and starting activities and receiving data from intentions. The following solutions show how you can deal with these problems during Android app development.

Android tutorial: how to unify data transfer between activities?

To fix this problem, we will create a model that will store all the required data. In order the whole thing to make sense, it should be given a single form. That’s why I wrote the NavigationBundle base model.

@Parcelize
open class NavigationBundle(val uuid: UUID = UUID.randomUUID())
    : Parcelable {
    class Empty : NavigationBundle()
}

It is an open class, so we are able to inherit from it and use it in generic arguments. It contains its own identifier and is marked with the parcelize annotation. The parcelize annotation comes from Kotlin Android extensions. For a class with this annotation, an implementation of the parcelable interface will be generated, thanks to which, we gain the ability to move data in intentions as parcelable using the putParcelable method. 

The nested empty class will serve us as the default empty value of the NavigationBundle. An example of the NavigationBundle:

class ProjectDetailsNavigationBundle(
    val projectId: UUID,
    val projectName: String,
    val projectBackgroundImageUrl: String
) : NavigationBundle()

For each activity, we write a class that contains all the necessary data (even if it is only one field).

Android tutorial: how can we unify the way of creating intentions and starting activities? 

Now we can go on to solve the next problem. We need to unify the method for creating intentions and starting activities. For that we’ll use higher-order functions and extension functionsCreating intentions:

inline fun  FragmentActivity.createIntent(
    bundle: NavigationBundle = NavigationBundle.Empty(),
    crossinline block: Intent.() -> Unit = {}
): Intent {
    val intent = Intent(this, T::class.java)
    val extras = Bundle()
    extras.putParcelable(KEY_NAVIGATION_BUNDLE, bundle)
    intent.putExtras(extras)
    return intent.apply(block)
}

This function is an extension for the FragmentActivity class and accepts three parameters:

  • The first is the generic type of activity to be started
  • The second is our previously described NavigationBundle
  • The third parameter is lambda, which allows you to modify the creation of an object of intent

We are able to create intentions in a uniform way throughout the application.

To solve our aforementioned problem, we need to write a function that will start an activity with a defined NavigationBundle.

Which looks like this:

inline fun  FragmentActivity.beginActivity(
    bundle: NavigationBundle = NavigationBundle.Empty(),
    crossinline block: Intent.() -> Unit = {}
) {
    val intent = this.createIntent(bundle, block)
    this.startActivity(intent)
}

In its design, it closely resembles the createIntent function, since it takes the same parameters. The difference is that this time we use the createIntent function to create an intention, and then start the activity by calling the startActivity method.

Android tutorial: how can we unify the method for receiving data from intention?

Our last problem is the unification of receiving data from intentions. You can do it in many ways, but we will again use extension functions.

inline fun  AppCompatActivity.getNavigationBundleOrNull(): T? {
    return intent.extras?.getParcelable(KEY_NAVIGATION_BUNDLE)
}

This function shortens the writing and improves its readability. We have solved the defined problem!

Starting another activity: revived

We already have all the necessary elements to our puzzle. So we can put them together to see the final result.

Let’s see if we can correct the example from the beginning of the article.

class ProjectsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_projects)
    }

    /** Called when the user taps the project item */
   fun showProjectDetails(project: Project) {
        val navigationBundle = ProjectDetailsNavigationBundle(
            project.id,
            project.name,
            project.backgroundImageUrl
        )
        beginActivity(navigationBundle)
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_project_details)
   
    // Get the Intent that started this activity and extract the value
    val navigationBundle =
        getNavigationBundleOrNull()

    
    // Capture the layout's TextView and set the string as its text
    val projectNameTextView = findViewById(R.id.projectNametextView)
        .apply {
            text = navigationBundle?.projectName
        }
}

Android tutorial: starting another activity – summary

In the Android tutorial, we went through steps allowing for better management of both the code and the Android app. Thanks to this approach, we will not have problems with non-uniform transfer or reception of data between activities, even in an extended platform.
The methods used make our code clearer, we have reduced its repetition, and in a way our activities require us to run them in a defined method.

How do you like the proposed solution? I encourage you to discuss in the comments below.

For more interesting content follow our blog and another article about Android development!

Slawomir Onyszko Mobile Developer

Sławek is our mobile developer who mostly takes care of creating Android applications. He is constantly enhancing his skills of advanced Android app development and he wants to share this knowledge via Zaven’s blog. In his spare time Sławek enjoys watching a good movie at the cinema.

Popular posts

From Hype to Hard Hats: Practical Use Cases for AI chatbots in Construction and Proptech.

From Hype to Hard Hats: Practical Use Cases for AI chatbots in Construction and Proptech.

Remember the multimedia craze in the early 2000s? It was everywhere, but did it truly revolutionize our lives? Probably not. Today, it feels like every piece of software is labeled "AI-powered." It's easy to dismiss AI chatbots in construction as just another tech fad.

Read more
Fears surrounding external support. How to address concerns about outsourcing software development?

Fears surrounding external support. How to address concerns about outsourcing software development?

Whether you’ve had bad experiences in the past or no experience at all, there will always be fears underlying your decision to outsource software development.

Read more
What do you actually seek from external support? Identify what’s preventing you from completing a project on time and within budget

What do you actually seek from external support? Identify what’s preventing you from completing a project on time and within budget

Let’s make it clear: if the capabilities are there, a project is best delivered internally. Sometimes, however, we are missing certain capabilities that are required to deliver said project in a realistic timeline. These may be related to skills (e.g. technical expertise, domain experience), budget (hiring locally is too expensive) or just capacity (not enough manpower). What are good reasons for outsourcing software development?

Read more
Mobile Apps

Get your mobile app in 3 easy steps!

1

Spec out

with the help of our
business analyst

2

Develop

design, implement
and test, repeat!

3

Publish

get your app out
to the stores


back to top