Programmatic Idioms recognized by Navigation Editor

As discussed in the overview, Android Studio's Navigation Editor works by parsing some of the XML resources and Java files in your project. This document is intended to remove some of the mystery of this process by setting out the templates that it uses to perform its analysis.

Application Structure

Navigation Editor's analysis starts with the project's AndroidManifest.xml file. Each Activity declared in the manifest file is examined, using the methods below, to find the set of menus, layout resources, and listeners associated with the Activity. Listeners that match one of the templates below are shown as transitions in Navigation Editor. For each 'destination' Activity found by the above techniques, Navigation Editor invokes the same procedure. Fragments found in the layout resources associated with each Activity are followed similarly. Navigation Editor calculates the 'transitive closure' of these relationships; i.e. links are followed until there are no more loose ends. 

In the sections below we go through the patterns Navigation Editor looks for as it parses Activities and Fragments.

Expression Syntax

The following conventions are used in the pattern matching descriptions below:
  • $token: a variable
  • token: a keyword (this must match exactly)
  • statement*: zero or more Java statements
[Note that in the current version of Navigation Editor, code snippets must appear literally in the methods indicated - i.e. the inference will not apply if the appropriate pattern is refactored into a another method. It is possible that later versions of Navigation Editor will follow method calls (and perhaps even compute a transitive closure of method invocations) so as to remove this restriction.]

Activity/Fragment -> Layout Resource

The relationship between Activities/Fragments and their associated layout resources is inferred from: 

Activities

void onCreate(Bundle $bundle) {
    statement
    setContentView($R.layout.$id);
    statement
}

Fragments

View onCreateView(LayoutInflater $inflater, ViewGroup $viewGroup, Bundle $bundle) {
    statement
    $inflater.inflate($R.layout.$id, $container, false);
    statement
}

Activity/Fragment -> Menu

The relationship between Activities/Fragments and their associated menu resources is inferred from

boolean onCreateOptionsMenu(Menu $menu) {
    statement
    getMenuInflater().inflate($R.menu.$id, $menu);
    statement
}

Transitions

MenuItem:itemClick()

The relationship between Activities/Fragments, their associated menus, menuItems and implied transitions is inferred from

boolean onPrepareOptionsMenu(Menu $menu) {
    statement
    $menu.findItem($R.id.$menuId).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem $menuItem) {
            $activity.startActivity(new Intent($activity, $DestinationActivity.class));
            return $consume;
        }
    });
    statement
}

View:click()

The relationship between general Views (e.g. Buttons) and their implied transitions is inferred from

void onCreate(Bundle $bundle) {
    statement
    findViewById($R.id.$id).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View $view) {
            $activity.startActivity(new Intent($activity, $DestinationActivity.class));
        }
    });
    statement
}

ListView:onItemClick()

The relationship between ListViews and their implied transitions is inferred from

ListFragment

void onViewCreated(View $view, Bundle $bundle) {
    statement
    getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> $parent, View $view, int $position, long $id) {
            statement
            $activity.startActivity(new Intent($activity, $DestinationActivity.class));      [statements may be embedded here]    
            statement
        }
    });
    statement
}

The Master-Detail pattern

The code generated by Android Studio's template system for 'Master-Detail' template is also parsed and 'understood' by Navigation Editor. The mechanisms for this inference are subject to change but will remain compatible with the code generated by the IDE for a new 'Master-Detail' Activity. 

How to tell Navigation Editor not to display an Activity for a particular Configuration

By default, Navigation Editor displays all those activities that are mentioned in the associated AndroidManifest.xml file. In some configurations, such as the master-details template above, this involves showing Activities in, for example, the 'tablet' mode that are not needed by an app running in this configuration. To remove them from the diagram created by the Navigation Editor, please follow the steps below. 

Create a special layout resource for that configuration whose top level component is Space, as follows (the comment is optional): 

<?xml version="1.0" encoding="utf-8"?>

<!-- Tell Navigation Editor not to display the associated Activity in this configuration -->

<Space xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent" />


Future Versions 


Over time the patterns above will be expanded accommodate more variations and any advances in recommended best practice. Policy for Navigation Editor will remain that it extends, rather than replaces, it's parsing abilities so that it will continue to be able to parse applications written by previous versions

Comments