ZOFTINO.COM android and web dev tutorials

Android Default Back Navigation & Customization

Like web browser’s back button takes you through previously visited web pages, Android system back button moves you through previous screens of an active app. Like back button functionality in web browser is provided by browser, Android back button functionality is provided by Android system. Both of them load previous pages or screens from cache or stack on clicking or touching back button.

To provide back navigation for your app, you don’t need to do anything. In most cases default back navigation is sufficient to provide perfect back navigational experience to users.

Below you can see back button provided by android system, it takes you back to previously worked activities or screens of currently active app in reverse chronological order.

”Android

Android back button default behavior

Android uses back stack to keep track of worked-on screens in chronological order. Back button functionality uses back stack to show previous screens and state on pressing it. Android system creates a new back stack when user starts an app by launching main activity from home screen. If the app is already open but inactive, system brings it to foreground and uses existing stack to resume current activity or top activity in the stack.

When current activity opens a new activity, the new activity is placed on top of the stack. New activity becomes active and the activity which started the new activity becomes inactive and stays in the stack.

If current activity opens a new activity which is already in the stack, system creates a new instance of the new activity and places it on top of the stock.

Android allows applications to start components of other apps. When another application opens an activity in your app, the activity is placed in the stack of the app which started your app activity.

When user presses back button, current activity is removed from the stack and destroyed and previous activity becomes current from the stack. All the activities placed in a stack are considered as a task.

Why to customize back navigation

Default back button functionality may not be suitable in some scenarios. In these cases, you may have to customize back button functionality to provide consistent navigation experience to users. Here are two scenarios where you need to provide custom back button functionality.

One of the best features of android is allowing multiple entries meaning even though there needs to be one main activity which is instantiated when app icon is pressed, app can be entered into by starting any activity in your app. For example, users can come to your app from app widget or notifications and navigate directly to a deep screen in the app hierarchy. In this scenario, default back button flow may not provide best user experience.

Apps can embed web browser on screens. When user navigates in the embedded browser and visits few web pages, you may want to change the default android back button behavior. Instead of taking user to previous screen, you may want it to navigate back through browser historical pages and then default behavior of going back to previously visited screens.

How to enhance or override android default back navigation

I am going to provide code for two scenarios in which you may need to provide different back navigation behavior than default one.

Scenario 1:

User starts an activity in a separate stack, from notification or widget, which is deep in app hierarchy. In this case, default back button exits the app as it is a new stack without previous screens. Instead of exiting the app, taking the user to either main screen or starting screen of current flow gives user an opportunity to continue using the app. That means you need to add activities to back stack.

Below is the code to show above scenario and implementation. The sample application has three screens, MainActivity screen, ViewCoupon screen and ViewStoreCoupons screen. MainActivity has a button to send notification. The method which handles the click event sets the parent stack for the Intent which is started when user clicks notification. Notice that parent activity (ViewStoreCoupons) is configured for ViewCoupon activity in AndroidManifest.xml file.

Below is the flow to test the sample app.

  1. Start the app
  2. Click “send notification” button on main screen
  3. View notification by dragging notification drawer
  4. Click notification, it opens ViewCoupon activity in separate stack
  5. Click back button, it takes you to parent activity , ViewStoreCoupons activity , instead of existing the app

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zoftino.backstack">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
        <activity android:name=".ViewStoreCouponsActivity">

        </activity>
        <activity android:name=".ViewCouponActivity"
            android:parentActivityName=".ViewStoreCouponsActivity" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ViewStoreCouponsActivity" />
        </activity>
    </application>

</manifest>

Main activity

package com.zoftino.backstack;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.NotificationCompat;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void sendNotification(View view){
        Context context = getApplicationContext();
        NotificationCompat.Builder nBuilder =
                new NotificationCompat.Builder(this);

        nBuilder.setSmallIcon(R.drawable.notification);
        nBuilder.setContentTitle("Mystore Coupon");
        nBuilder.setContentText("Get Upto 20% Off on travel booking");

        Intent nIntent = new Intent(this, ViewCouponActivity.class);

        PendingIntent nPendingIntent =
                TaskStackBuilder.create(this)
                        //adds parent stack
                        .addNextIntentWithParentStack(nIntent)
                        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);


        nBuilder.setContentIntent(nPendingIntent);
        NotificationManager mNotificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotificationManager.notify(11, nBuilder .build());

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.zoftino.backstack.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Notification MainActivity"
        android:id="@+id/textView" ></TextView>

    <Button
        android:text="Send Coupon Notification"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView"
        android:layout_toRightOf="@+id/textView"
        android:layout_toEndOf="@+id/textView"
        android:layout_marginTop="97dp"
        android:onClick="sendNotification"
        android:id="@+id/sendNotification" ></Button>
</RelativeLayout>

View coupons activity

 package com.zoftino.backstack;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;


public class ViewCouponActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.coupon_view);
    }
} 

coupon_view.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:text="MyStore Coupon"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/storecpn" ></TextView>

    <TextView
        android:text="Get Upto 20% Off on travel booking"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/coupon" ></TextView>
</LinearLayout> 

View all coupons activity

 package com.zoftino.backstack;


import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class ViewStoreCouponsActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.allcoupons_view);
    }
} 

allcoupons_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:text="MyStore All Coupons"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/mystoreallcpn" ></TextView>

    <TextView
        android:text="Get Upto 20% Off on travel booking"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/cpnone" ></TextView>

    <TextView
        android:text="Flat 50% off on hotels"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/cpntwo" ></TextView>

    <TextView
        android:text="Upto 80% off on flights"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/cpnthree" ></TextView>
</LinearLayout>

Scenario 2:

You may want to change the default back navigation behavior for the screens which contain WebView. Default back button takes user to previously visited screens. You can override this behavior to call the browser back button to traverse browser history and then to traverse stack of the app.

You need to override onBackPressed method of the activity which embeds browser on the screen.

@Override
public void onBackPressed() {
    if (myWebView.canGoBack()) {
        myWebView.goBack();
        return;
    }
    super.onBackPressed();
}