All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neovisionaries.android.app.BaseRootActivity Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012-2014 Neo Visionaries Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.neovisionaries.android.app;


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.neovisionaries.android.util.L;


/**
 * Base class for a root Activity of an application whose all the other
 * Activities honor the chain of {@code finish()} mechanism.
 *
 * 

* A subclass of this class is expected to be set as the main activity in * {@code AndroidManifest.xml} like the following. *

* * * *
 * <activity android:name=".RootActivity" >
 *     <intent-filter>
 *         <action android:name="android.intent.action.MAIN" />
 *         <category android:name="android.intent.category.LAUNCHER" />
 *     </intent-filter>
 * </activity>
* *

* Sub classes are required to implement {@link #dispatch()} method which is * expected to launch another Activity. A simple example of a root Activity * that extends {@code BaseRootActivity} is shown below. *

* * * *
 * public class RootActivity extends BaseRootActivity
 * {
 *     @Override
 *     public void onCreate(Bundle savedInstance)
 *     {
 *         super.onCreate(savedInstance);
 *
 *         setContentView(R.layout.root_activity);
 *     }
 *
 *     @Override
 *     protected void dispatch()
 *     {   
 *         // Start HomeActivity. Activities launched from here
 *         // should call App.getInstance().setStopping(true)
 *         // when they receive a key down event of KEYCODE_BACK.
 *         // Otherwise, such Activities will be re-launched by
 *         // the onResume() implementation of BaseRootActivity.
 *         // You may find BottomActivity and its variants useful.
 *         startActivity(new Intent(this, HomeActivity.class));
 *
 *         // Note that finish() should not be called here.
 *         // This RootActivity instance should sit at the
 *         // bottom of the Activity stack in order to benefit
 *         // from the default mechanism of Android's Activity
 *         // management.
 *     }
 * }
* *

* The implementation of {@link #onDestroy()} method of this class * does the following to support restarting. *

* *
    *
  1. Emit a log message saying "STOPPED". *
  2. Check if the application is in the process of restart * (= check if {@link App}{@code .}{@link App#getInstance() * getInstance()}{@code .}{@link App#isRestarting() * isRestarting()} returns {@code true}). *
  3. If the application is in the process of restart, create an * {@link Intent} with {@link Intent#ACTION_MAIN ACTION_MAIN} * & {@link Intent#CATEGORY_LAUNCHER CATEGORY_LAUNCHER} * and pass it to {@link #startActivity(Intent)}, and the call * {@link App}{@code .}{@link App#getInstance() getInstance()}{@code * .}{@link App#setRestarting(boolean) setRestarting}{@code (false)}. *
* * @author Takahiko Kawasaki */ public abstract class BaseRootActivity extends Activity { /** * Called when this Activity gets resumed. * The implementation of this method does the following. * *

*
    *
  1. Calls {@code super.onResume()}.

    *
  2. Calls {@code App.getInstance().}{@link App#isStopping() isStopping()} * and if the return value is true, calls {@code finish()} and executes * {@code App.getInstance().}{@link App#setStopping(boolean) * setStopping}{@code (false)}. The {@code finish()} call terminates * this application (if the subclass of BaseRootActivity is used as the * root Activity). The reason to call {@code App.getInstance().setStopping(false)} * is that Android may reuse this Activity instance instead of creating * a new one.

    *
  3. Otherwise, calls {@link #dispatch()} that subclasses must implement. *

    *
* *

* Note that if a subclass of {@code BaseRootActivity} is used as the root * Activity, the application won't terminate until {@code * App.getInstance().}{@link App#setStopping(boolean) setStopping}{@code * (true)} is explicitly called. You may find {@link BaseActivity#exit()} * useful to stop your application. *

*/ @Override protected final void onResume() { super.onResume(); App app = App.getInstance(); if (app.isStopping()) { // Close this Activity, meaning that this application is closed // because this Activity is the root. finish(); // Reset the termination state because Android may reuse this // Activity instance instead of creating a new one. app.setStopping(false); } else { // Reset the restart state for the case where onDestroy() has // failed to be called during the last restart process. app.setRestarting(false); // Launch another Activity. dispatch(); } } /** * Launch another Activity. * *

* This method is called from the context of {@code onResume()} if and * only if {@code App.getInstance().}{@link App#isStopping() isStopping()} * returned false when {@code onResume()} of this Activity was called. * Implementations of this method are expected to invoke another Activity. *

* *

* Note that implementations of this method should not call {@code finish()} * after invoking another Activity. It is because the purpose of the root * Activity is to sit at the bottom of the Activity stack so that this * application can benefit from the default mechanism of Android's Activity * management. *

* *

* Activities launched from within {@code dispatch()} method should call * {@code App.getInstance().setStopping(true)} when they receive a key * down event of {@code KEYCODE_BACK}. Otherwise, such Activities will * be re-launched by the {@code onResume()} implementation of * {@code BaseRootActivity}. A simple way to satisfy the requirement is * to use {@link BottomActivity} or its variants whose {@code onKeyDown} * method calls {@code App.getInstance().setStopping(true)}. *

*/ protected abstract void dispatch(); /** * Called when this Activity gets started. * *

* This method is the best point to re-initialize the application. * In other words, this is the logical starting point of the application. * (The 'physical' starting point of the * application is {@code onCreate()} of {@code android.app.Application}.) * *

* *

* The implementation of this method emits "STARTED" log message. *

* * @see BaseApplication#onCreate() */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); log("STARTED"); } /** * Called when this Activity gets stopped. * *

* This method is the best point to finalize the application. * In other words, this is the logical end point of the application. * (The 'physical' end point of the * application is {@code onTerminate()} of {@code android.app.Application}.) * *

* *

* The implementation of this method emits "STOPPED" log message. * And then, if required (= if {@link App}{@code .}{@link App#getInstance() * getInstance()}{@code .}{@link App#isRestarting() isRestarting()} returns * {@code true}), this implementation restarts {@code this} activity by * passing an {@link Intent} with {@link Intent#ACTION_MAIN ACTION_MAIN} * & {@link Intent#CATEGORY_LAUNCHER CATEGORY_LAUNCHER} to * {@link #startActivity(Intent)}. In such a case, "RESTARTING" log * message is emitted. *

* * @see BaseApplication#onTerminate() */ @Override protected void onDestroy() { log("STOPPED"); if (App.getInstance().isRestarting()) { log("RESTARTING"); // Trigger this activity to be launched as if it started // from the launcher. startActivity(createMainLauncherIntent()); // Reset the restart state because Android may reuse this // Activity instance instead of creating a new one. App.getInstance().setRestarting(false); } super.onDestroy(); } /** * Emit a log message related to the application's life cycle. */ private void log(String state) { // App instance. App app = App.getInstance(); // Emit a log message related to the application's life cycle. L.d(this, "== APPLICATION '%s' (version = %s) %s ==", app.getApplicationLabel(), app.getVersionName(), state); } /** * Create an {@link Intent} with {@link Intent#ACTION_MAIN ACTION_MAIN} * & {@link Intent#CATEGORY_LAUNCHER CATEGORY_LAUNCHER} to launch * {@code this} activity. */ private Intent createMainLauncherIntent() { Intent intent = new Intent(); // To launch this activity as if it started from the launcher. intent.setClass(this, getClass()); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); return intent; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy