3

I structure my Android application following Uncle Bob's Clean Architecture which basically comprise of at least following relevant layers:-

  • Presentation - Using MVVM approach. This layer contains Android's Activities and their corresponding ViewModels.
  • Interactor - This layer encapsulates application's use cases logic and basically being called from several ViewModels to achieve business-specific tasks. It can also keep state that reflects the progress of a task.

Currently, there are a handful of use cases or workflows in my application. Each workflow will go through a specific sequence of pages (i.e. Activities or Fragments). As it has only few pages and workflows, it's simply just make sense to put navigation logic inside each ViewModel explicitly. Let's say there is a use case A that goes through following Activities:-

Use Case A [HomeActivity] --> [ActivityA] --> [ActivityB]

Imagine that the ActivityA presents a user with some list of items for selection for which it will be acted upon in the ActivityB. In the ActivityA, I just simply call

startActivity(new Intent(this, ActivityB.class))

to navigate to ActivityB when user has done selecting an item and already called an interactor to keep state of which item being selected by a user.

...

Now the problem arises, a business needs a new use case B which draws a different workflow but reuses the same ActivityA in its workflow.

Use Case B [HomeActivity] --> [ActivityA] --> [ActivityC]

As you can see, now the ActivityA can navigate to not just the ActivityB but also the ActivityC depending on which use case it's being participated in. While most of the logic in ActivityA as well as its view XML and its ViewModel is generic enough to be reused in both use cases, the navigation part is not.

How can I cope with this navigation issue so that the code in ActivityA and its related elements is generic enough to be reused in any workflow? What is the most elegant solution from your idea?

1

If I understand you correctly, you are choosing which activity to go to after activityA before starting activityA?

The simplest solution I can think of is to inherit from activityA and override a method like goToNextActivity(). This might get a bit hard to understand in the future though. Another might be to make the concept of the "workflow" explicit. You could name them and then give it to the activity as an extra. An activity could then call a utility method somewhere like Navigation.goToNextScreen(this,workflow). The navigation method could then decide where to go after each activity in which workflow and also set the extras containing the workflow.

  • "If I understand you correctly, you are choosing which activity to go to after activityA before starting activityA?" >> Exactly yes. It needs to determine before starting ActivityA. – onelaview Feb 17 '18 at 1:33
  • I like your idea to make the "workflow" concept explicit. The difficult part is that this workflow instance must keep and manage state like which page (activity or fragment) is current being active and in which workflow. It also needs to aware that user can also navigate back or even navigate across to start a new different workflow at anytime while it may be possible to return back to the original workflow and resume pending outer workflow task. Very difficult to implement I think but very worth a try. – onelaview Feb 17 '18 at 1:33
1

I see multiple useable approaches.

First Thing is to Identify your ActivityB as a Value Picker Control and treat it like one. This thing should be general purpose, so every behaviour should be configurable from the outside.

The easier way to make this thing reusable in different places it by inheritence, like, like @Hendrik Marx already suggested.

So you have an abstract BaseActivityB and two implementations who just override a method you call when the navigation should start.

The second, more complex option is to make ActivityB read some bundle parameters in it's onCreate and later decide based on these parameters, where it should navigate to.

I'd strongly recommend the inheritance approach, as you make the different usages very explicit. Also, when you use parameters bundled with the Intent, it means you put a lot of different navigation logic into one class (think of the Single Responsibility Principle).

  • I assume you mean to identifying ActivityA (not ActivityB) as a Value Picker Control, right? Because ActivityA will pick some value and then navigate to either ActivityB or ActivityC. – onelaview Feb 17 '18 at 1:19
1

In my opinion the "workflow" is either part of the businesslogic or a layer on it-s own above the businisslayer ("service layer").

The viewModell is responsible to communicate with the gui.

Assume you have an online shop that sells food and cigaretts.

The Workflow logic may have a boolean function customerMustBeOlderThan18Years()

The viewModel would have a method getActivityIntentForNextCommand() that returns an intent to "ProveThatCustomerIsOlderThan18YearsActivity" if there are ciragretts in the shopping cart.

  • If I get you correctly, you also suggested to explicitly introduce workflow concept somewhere else and not put this logic in a view model, right? Otherwise, view model will be dirty with the navigation logic to determine which is the next activity/fragment to navigate to. – onelaview Feb 17 '18 at 1:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.