测试 onSaveInstanceState

覆盖 onSaveInstanceState(Bundle) 方法时,应测试 activity 状态是否如预期正确保存和恢复。使用模拟器很容易做到这些。方法时在模拟器的 Dev Settings 中找到并启用 Don’t keep activities 选项,如下图所示:

t keep activities 选项

打 Log

使用 android.util.Log 类记录日志信息,不仅可以控制日志信息的内容,还可以控制用来划分信息重要程度的日志级别。Android 支持如下图所示的五种日志级别。每一个级别对应着一个Log类方法。调用对应的Log类方法与日志的输出和记录一样容易,如下表所示:

Log Level Method 说明
ERROR Log.e(…) 错误
WARNING Log.w(…) 警告
INFO Log.i(…) 信息型消息
DEBUG Log.d(…) 调试输出:可能被过滤掉
VERBOSE Log.v(…) 只用于开发

需要说明的是,所有的日志记录方法都有两种参数签名:string 类型的 tag 参数和 msg 参数;除 tag 和 msg 参数外再加上 Throwable 实例参数。附加的 Throwable 实例参数为应用抛出异常时记录异常信息提供了方便。

下面的代码展示了两种方法不同参数签名的使用实例。对于输出的日志信息,可使用常用的 Java 字符串连接操作拼接出需要的信息。或者使用 String.format 对输出日志信息进行格式化操作,以满足个性化的使用要求。

1
2
3
4
5
6
7
8
9
10
// Log a message at "debug" log level
Log.d(TAG, "Current question index: " + mCurrentIndex);
TrueFalse question;
try {
question = mQuestionBank[mCurrentIndex];
} catch (ArrayIndexOutOfBoundsException ex) {
// Log a message at "error" log level, along with an exception stack trace
Log.e(TAG, "Index was Out of bounds", ex);
}

API 兼容

在 Android 平台的一个系统版本中调用了该版本中不存在或不合适的系统 API ,必然会出现调用失败或运行结果不符合预期,进而导致软件运行发生 Crash 或产生错误。

示例

对于如下代码:

1
2
3
4
private void setUpActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}

该方法中,调用了当前版本不存在的 ActionBar.setDisplayHomeAsUpEnabled() 方法。

推荐方案

在这些 API 使用时,加上 Android 系统版本判断,避免不兼容 API 的调用。

1
2
3
4
5
6
7
8
9
10
11
12
private void setUpActionBar() {
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// 包含新API的代码块
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
else
{
// 包含旧的API的代码块
}
}

Build.VERSION.SDK_INT 常量代表了 Android 设备的版本号。可将该常量同代表 Honeycomb 版本的常量进行比较。(版本号清单可参考 Build.VERSION_CODES )

Android 开发设计原则

网址 Up and running with material design 罗列了 Android 所有的开发设计原则。

组件 ID 与多布局

有时,设备处于不同方向时使用的布局会有很大差异。如发生这种情况,应在保证组件已确实存在后,再在代码中引用它们。

如果一个组件只存在于一个布局上,则需先在代码中进行空值检查,确认当前方向的组件存在后,再调用相关方法:

1
2
3
4
Button landscapeOnlyButton = (Button)v.findViewById(R.id.landscapeOnlyButton);
if (landscapeOnlyButton != null) {
// Set it up
}

最后,请记住,定义在水平或竖直布局文件里的同一组件必须具有同样的 android:id 属性,这样代码才能引用到它。

创建单例

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CrimeLab {
private static CrimeLab sCrimeLab;
private Context mAppContext;
private CrimeLab(Context appContext) {
mAppContext = appContext;
}
public static CrimeLab get(Context c) {
if (sCrimeLab == null) {
sCrimeLab = new CrimeLab(c.getApplicationContext());
}
return sCrimeLab;
}
}

CrimeLab 类的构造方法需要一个 Context 参数,这在 Android 开发里很常见,使用 Context 参数,单例可完成启动 activity 、获取项目资源,查找应用的私有存储空间的任务。在 get(Context) 方法里,我们将 application context 传给构造方法。application context 是针对应用的全局性 Context 。任何时候,只要是应用层面的单例,就应该一直使用 application context。

Comments