即使代码清单1-1中没有任何与用户交互的代码,仍然可以视活动为用户交互的基本单位,因为它代表全屏的用户交互。
在随后的章节中,将看到应用程序中的Fragment子类如何处理用户交互。
Activity类是Android的用户交互的卡堆比喻(card-stack metaphor)的基础,活动之间的导航是用户交互的重要组成部分。该Activity子类是应用程序的主活动。这就是当用户触摸应用程序的图标时,应用程序启动的地方,因此,这位于应用程序备用栈的底部。
代码清单1-1:MainActivity.java package com.enterpriseandroidbook.fragmentframework; import android.app.ActionBar; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; /** * @author zigurd * */ public class MainActivity extends TabbedActivity { // String for logging the class name private final String CLASSNAME = getClass().getSimpleName(); // Turn logging on or off private final boolean L = true;
这个示例中的生命周期方法的代码在这里是为了帮助可视化应用程序生命周期。可视化应用程序生命周期非常重要,因为它很容易被忽视。为了规划你的应用程序更好地适应组件的生命周期,你应该想知道通过组件生命周期查看Android OS对你的应用程序做了什么。
下面的onCreate()方法中的代码首先调用父类的方法,然后添加子类的特定代码。在这个示例中,代码记录了该方法调用的日志,并记录了该方法是否是第一次被调用以创建这个Activity实例的日志,或者前一个实例是否已经存在,并且该实例的状态是否应该恢复(更多信息,等到你知道一些其他的生命周期方法之后就会明白)。在onCreate()方法中要执行的大部分工作被分解出来放在doCreate()方法中。它加载布局,设置操作栏(action bar),并初始化操作栏中的选项卡。
@Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); // To keep this method simple doCreate(savedState); // If we had state to restore, we note that in the log message if (L) Log.i(CLASSNAME, "onCreate" + (null == savedState ? " Restored state" : "")); } @Override protected void onRestart() { super.onRestart(); // Notification that the activity will be started if (L) Log.i(CLASSNAME, "onRestart"); } @Override protected void onStart() { super.onStart(); // Notification that the activity is starting if (L) Log.i(CLASSNAME, "onStart"); } @Override protected void onResume() { super.onResume(); // Notification that the activity will interact with the user if (L) Log.i(CLASSNAME, "onResume"); } protected void onPause() { super.onPause(); // Notification that the activity will stop interacting with the user if (L) Log.i(CLASSNAME, "onPause" + (isFinishing() ? " Finishing" : "")); } @Override protected void onStop() { super.onStop(); // Notification that the activity is no longer visible if (L) Log.i(CLASSNAME, "onStop"); }
如下面的代码所示,onDestroy()方法的代码在调用该方法时记录了日志。该方法名onDestroy()造成了一些混乱。什么被销毁?其实此刻发生的是Android系统对该Activity子类的实例的引用执行“销毁”或设置为null,从而导致可以对该实例进行垃圾回收。你可能认为只要持有该Activity实例的引用就能阻碍销毁它。但这是行不通的:销毁该实例后,Android系统将创建这个活动的一个新实例,而不管是否持有它的引用。你可以阻止已经没用的实例被垃圾回收器回收,但是它已经是僵尸,在堆中占用宝贵的内存。请注意, onDestroy()方法测试和记录该活动是否“结束”的日志——意思是Activity的该实例将不会被重建,因为它已经使用完,而不是因为销毁它以恢复内存空间。
@Override protected void onDestroy() { super.onDestroy(); // Notification the activity will be destroyed if (L) Log.i(CLASSNAME, "onDestroy" // Are we finishing? + (isFinishing() ? " Finishing" : "")); }
以下是onSaveInstanceState()方法的代码,它输出被调用的下一个日志。请注意,把一个Bundle对象传递给这个方法。该Bundle对象使你能够追加实现Parcelable接口的序列化对象。因为该Bundle对象本身实现Parcelable接口,所以它和所有其持有引用的对象可以序列化并存储——或以Java的说法是“持久化”。
这就是传递给onCreate()方法中Bundle对象的由来。如果向它添加了对象,当调用onCreate()和onRestoreInstanceState()时将对象作为参数传入。
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); saveState(outState); // Called when state should be saved if (L) Log.i(CLASSNAME, "onSaveInstanceState"); } @Override protected void onRestoreInstanceState(Bundle savedState) { super.onRestoreInstanceState(savedState); if (null != savedState) restoreState(savedState); // If we had state to restore, we note that in the log message if (L) Log.i(CLASSNAME, "onRestoreInstanceState" + (null == savedState ? " Restored state" : "")); } ////////////////////////////////////////////////////////////////////////// // The minor lifecycle methods - you probably won't need these ////////////////////////////////////////////////////////////////////////// @Override protected void onPostCreate(Bundle savedState) { super.onPostCreate(savedState); if (null != savedState) restoreState(savedState); // If we had state to restore, we note that in the log message if (L) Log.i(CLASSNAME, "onCreate" + (null == savedState ? " Restored state" : "")); } @Override protected void onPostResume() { super.onPostResume(); // Notification that resuming the activity is complete if (L) Log.i(CLASSNAME, "onPostResume"); } @Override protected void onUserLeaveHint() { super.onUserLeaveHint(); // Notification that user navigated away from this activity if (L) Log.i(CLASSNAME, "onUserLeaveHint"); } /////////////////////////////////////////////////////////////////////// // Overrides of the implementations ComponentCallbacks methods in Activity /////////////////////////////////////////////////////////////////////// @Override public void onConfigurationChanged(Configuration newConfiguration) { super.onConfigurationChanged(newConfiguration); // This won't happen unless we declare changes we handle in the manifest if (L) Log.i(CLASSNAME, "onConfigurationChanged"); } @Override public void onLowMemory() { // No guarantee this is called before or after other callbacks if (L) Log.i(CLASSNAME, "onLowMemory"); } /////////////////////////////////////////////////////////////////////// // App-specific code here /////////////////////////////////////////////////////////////////////// /** * This is where we restore state we previously saved. * @param savedState the Bundle we got from the callback */ private void restoreState(Bundle savedState) { // Add your code to restore state here } /** * Add this activity's state to the bundle and/or commit pending data */ private void saveState(Bundle state) { // Add your code to add state to the bundle here } /** * Perform initializations on creation of this Activity instance * @param savedState */ private void doCreate(Bundle savedState) { setContentView(R.layout.main); if (null != savedState) restoreState(savedState); ActionBar bar = getActionBar(); bar.setDisplayShowTitleEnabled(false); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Initialize the tabs (Fails silently if the tab fragments don't exist) int names[] = {R.string.item, R.string.detail }; int fragments[] = { R.id.content_frag, R.id.detail_frag }; initializeTabs(0, names, fragments); } }
上面的代码包含生命周期方法onRestart()、onStart()、onResume()、onPause()和OnStop()的实现。像这个示例中其他重要的生命周期方法一样,当调用这些回调方法时记录了日志。当活动变得可见或被屏幕上的其他活动覆盖时,这些方法将通知你。你将发现当对照Android文档中描述活动生命周期的图表查看这些图中发生的状态转换时,在Eclipse IDE的logcat中观察这些日志消息非常有用。参考http://developer.android.com/training/basics/activity- lifecycle/starting.html。
请注意,保存状态不需要使用Bundle对象。在Android中保存状态有三种基本的方式。
●恢复状态——如果状态是数据库查询的结果,就可以在束(bundle)中保存该查询(或甚至恢复查询,例如,基于一天的时间),并重新运行它。
●在数据库中保存状态——如果状态保存在应用程序运行的设备的本地数据库中,当组件重建时,就可以从该数据库读取。
●把它放在束中——如前所述,可在Bundle对象中保存状态。
在大多数重要的应用中程序,都应用了这些方法的组合。保存状态的需求会影响Android应用程序的设计方法。SQLite数据库中主要的数据模型是最小化应用程序状态保存需求的一种便利方式。把数据库放在ContentProvider对象中,而从Activity对象中移除数据库。ContentProvider API实现了一个简单的观察者模式,并且它跟踪了全书中详细阐述的一个设计模式,这里本地数据库被同步到网络数据库。