以下文字来源于andoid SDK上一篇文章的大概翻译:
当你的应用里显示了一堆数据,这些数据又是开销较大获取的, 在configuration变换如键盘弹出隐藏,横竖屏切换,语言变换等出现时,系统自动的Activity destroy/creation 机制可能会导致非常不好的用户体验。 比如如下的例子,一个简单的Fclikr浏览应用,其从网上下载你账户里的图片。
如上述横竖屏切换时,如果不做特殊处理,android会自动处理 configuration变换事件,但是, 这样的话应用如果重新下载要显示的图片,用户体验该是多么糟糕。 明显的解决这个问题的办法是cache一下这些图片。 可以cahce这些图片到 SD card里(如果有的话), 或在应用程序的数据对象里, 或在静态数据里等等。 不过前述这些方法都不太适合于这个问题:
为什么我们要有开销来cache这些图片当屏幕没有横竖屏切换?
幸运的是,Android提供了一个极好的API, 用来处理这个问题。
Activity 类有一个特别的方法,叫 onRetainNonConfigurationInstance()
. 该方法可以用来传递一个任意的对象, 你的应用可以在将来需要时调用此方法。 在上面的应用里,可以将下载的图片通过此接口传递。实现类似如下:
@Override
public Object onRetainNonConfigurationInstance() {
final LoadedPhoto[] list = new LoadedPhoto[numberOfPhotos];
keepPhotos(list);
return list;
}
在横竖切换后,新创建的Activity里的onCreate函数,你要做的是是将你的对象取回来,通过getLastNonConfigurationInstance() 接口。
private void loadPhotos() {
final Object data = getLastNonConfigurationInstance();
// The activity is starting for the first time, load the photos from Flickr
if (data == null) {
mTask = new GetPhotoListTask().execute(mCurrentPage);
} else {
// The activity was destroyed/created automatically, populate the grid
// of photos with the images loaded by the previous activity
final LoadedPhoto[] photos = (LoadedPhoto[]) data;
for (LoadedPhoto photo : photos) {
addPhoto(photo);
}
}
}
要注意的是, 传递给onRetainNonConfigurationChange()
的对象,不能是跟Activity/Context有关联的, 否则将会有内存泄露所有跟Activity相关联的view和resource。 也即意味着,你不能传递如View, Drawable, Adapter 等等对象。上述应用传递的是图片bitmap本身,而不是drawable. 最后,还是注意的是,你应该仅用该接口传递较“珍贵”的数据(重新获取代价较大)。
另外,SDK中还有说明如下:
该 接口仅供优化调用,你不能仅仅依靠此接口。 当其被调用时,有一系列保证措施会用来帮助优化configuration切换:
1) 接口将在onStop()和onDestroy()之间调用。
2) 一个新的Activity的实例一般会立即生成,在当前Activity的onDestory()被调用后。 特别是,在这段时间没有消息会被分发(返回的对象没有关联于一个activity).
3) 返回的对象一般将在接下来系统自动重新的Activity实例里通过getLastNonConfigurationInstance()
接口获得。
这些保证设计用来使一个activity可以将扩展的状态从旧的activity传递到新的activity实例,包括加载的图片,网络连接对象,甚至是正在运行的线程对象。 注意不要传递任何将根据configuration变换的对象,如 对resource里读取的string, layout, drawable等。