Android应用开发:Fragment与大型数据缓存

来源:互联网 发布:2017网络水军招募 编辑:程序博客网 时间:2024/04/29 17:21

引言

在Android应用开发:Fragment的非中断保存setRetaineInstance一文中已经介绍过了如何让Fragment不随着Activity销毁从而保存数据的方法。在移动应用程序的架构设计中,界面与数据即不可分割又不可混淆。在绝大部分的开发经历中,我们都是使用Fragment来进行界面编程,即使保存数据基本上也只是界面相关控件的数据,很少做其他的数据保存,毕竟这样与开发原则相背,而今天这一篇博客就要来介绍一下Fragment的另类用法,只是用来保存数据而没有任何界面元素。
实现背景

对于Fragment的数据保存方法,不难想到还是与setRetainInstance有关系的。这样一来所处的背景也是在屏幕旋转或其他配置改变时需要用到。无论在开发中我们的界面是用Activity还是Fragment生成的,在屏幕发生旋转时,都会在生命周期onSaveInstanceState中做控件状态和必要数据的缓存工作。通常情况下,会用到Bundle来存储数据。如Bundle的官方介绍所说,Bundle是一个用来存储String及其他序列化数据类型的map。同样Android中也存在着这样的一个异常:http://developer.android.com/intl/zh-cn/reference/android/os/TransactionTooLargeException.html

这个异常从字面上看不难理解,是传输数据过大异常。在描述中可知,现行Android系统中对于应用程序的传输数据大小限制在1Mb以内。所以如果在屏幕旋转过程中使用Bundle缓存大数据并不是十分安全的。这样的大数据在Android中很经典的代表之一就是Bitmap,即使Bitmap已经是序列化数据,能够方便的使用Bundle作为缓存媒介,但是笔者还是强烈不建议这样做。下边,就提供一个简单的解决途径。

实现过程

首先,创建一个用来保存数据的Fragment:

public class BitmapDataFragment extends Fragment {    public static final String TAG = "bitmapsaver";    private Bitmap bitmap;    private BitmapDataFragment(Bitmap bitmap) {        this.bitmap = bitmap;    }    public static BitmapDataFragment newInstance(Bitmap bitmap) {        return new BitmapDataFragment(bitmap);    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setRetainInstance(true);    }    public Bitmap getData() {        return bitmap;    }}

这个Fragment没有任何界面,在onCreate生命周期中使用setRetainInstance(true)确保不会随载体销毁,从而确保数据的安全性。

创建完成后,实践一下使用过程,假设其使用者是Activity:

@Override    protected void onSaveInstanceState(Bundle outState) {        if (mBitmap != null) {            getSupportFragmentManager().beginTransaction()                    .add(BitmapDataFragment.newInstance(mBitmap), BitmapDataFragment.TAG)                    .commit();            outState.putBoolean(SENSE_IMAGE_KEY, true);        } else {            outState.putBoolean(SENSE_IMAGE_KEY, false);        }        super.onSaveInstanceState(outState);    }

在设备发生旋转时,检测当前界面中显示的某个Bitmap,如果确实有数据,则new出一个我们刚刚创建的Fragment,将Bitmap数据放置进去,然后将这个Fragment添加到FragmentManager中并指定tag,这样我们在恢复状态后就可以方便的找到它。

在恢复时候,Activity的生命周期走到了onCreate()中,在这里我们可以通过检测Bundle参数来确定是否有Bitmap数据待取:

if (savedInstanceState.getBoolean(SENSE_IMAGE_KEY)) {     BitmapDataFragment fragment = (BitmapDataFragment) getSupportFragmentManager()         .findFragmentByTag(BitmapDataFragment.TAG);     bitmap = fragment.getData();     getSupportFragmentManager().beginTransaction().remove(fragment).commit();}

PS:在取出我们所需的Bitmap数据后不要忘记把作为数据容器的这个Fragment从FragmentManager中移除掉,释放其占用的系统内存。

总结

很简单的Fragment非主流用法,相比直接使用Bundle保存数据确实是复杂了些,但是能够更安全的进行数据转移对应用来说还是很好的一件事。

0 0