Android Configuration 变换时如何保持珍贵数据不被摧毁
以下文字来源于andoid SDK上一篇文章的大概翻译:
?
当你的应用里显示了一堆数据,这些数据又是开销较大获取的, 在configuration变换如键盘弹出隐藏,横竖屏切换,语言变换等出现时,系统自动的Activity destroy/creation 机制可能会导致非常不好的用户体验。 比如如下的例子,一个简单的Fclikr浏览应用,其从网上下载你账户里的图片。
?

?

?
?
如上述横竖屏切换时,如果不做特殊处理,android会自动处理 configuration变换事件,但是, 这样的话应用如果重新下载要显示的图片,用户体验该是多么糟糕。 明显的解决这个问题的办法是cache一下这些图片。 可以cahce这些图片到 SD card里(如果有的话), 或在应用程序的数据对象里, 或在静态数据里等等。 不过前述这些方法都不太适合于这个问题:
为什么我们要有开销来cache这些图片当屏幕没有横竖屏切换?
?
幸运的是,Android提供了一个极好的API, 用来处理这个问题。
?
Activity 类有一个特别的方法,叫 onRetainNonConfigurationInstance(). 该方法可以用来传递一个任意的对象, 你的应用可以在将来需要时调用此方法。 在上面的应用里,可以将下载的图片通过此接口传递。实现类似如下:
?
@Overridepublic 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等。