★ Android基础篇 Android 数据存储与性能

★ Android基础篇 Android 数据存储与性能

前言

最近到了一家公司,跟一个同事做项目,比如常规的一些操作用SharedPreferences就很好搞定,他跟我说SharedPreferences 会影响性能说了一堆… 难道别的存储方式就不耗费性能吗?不消耗内存吗?

有关Android存储

Android中的数据存储方案主要有:共享首选项(SharedPreferences)、内部存储(Internal Storage)、外部存储(External Storage)、SQLite数据库、 网络存储 静态变量等

SharedPreferences 共享首选项

先说一下SharedPreferences 简称SP , SharedPreferences类提供了一个通用框架,使开发者能够以键值对的方式,永久性的保存一些原始数据类型的数据,包括:布尔值,浮点值,整型值,长整型和字符串,被保存的数据可以跨多个用户会话永久保留(即使应用已经终止)。

为什么使用 SP 它的优点是什么? 使用SP 为Android开发者提供了更为便利的存储方式,但是相对的他也是有一些缺点的。

当我们首次创建 SharedPreferences 对象时,会根据文件名将文件下内容一次性加载到 mMap(SharedPreferencesImpl 成员) 容器中,每当我们 edit 都会创建一个新的 EditorImpl 对象,当修改或者添加数据时会将数据添加到 mModifiled (EditorImpl 成员)容器中,然后 commit 或 apply 操作比较 mMap 与 mModifiled 数据修正 mMap 中最后一次提交数据,然后写入到文件中。而 get 直接从 mMap 中读取。试想如果此时你存储了一些大型 key 或 value 它们会一直存储在内存中得不到释放。

(1) 不要存放大的 key 和 value 在 SharedPreferences 中,否则会一直存储在内存中得不到释放,内存使用过高会频发引发GC,导致界面丢帧甚至ANR
(2) 不相关的配置选项最好不要放在一起,单个文件越大读取速度则越慢。
(3) 读取频繁的 key 和不频繁的 key 尽量不要放在一起(如果整个文件本身就较小则忽略,为了这点性能添加维护得不偿失)。
(4) 尽量不要存放 JSON 和 HTML,这种可以直接文件缓存。Json/HTML 文件较小忽略不计!
(5) 不要指望这货能够跨进程通信 Context.PROCESS

静态变量存储方式

因为这种方式我与我一个同事有了一些意见不一的地方,他喜欢使用静态变量。现在的开发是针对于设备开发,而并非手机app的开发,如果app开发他的那种搞法非得出现问题不可。
因为Activity初始化的静态变量也会被置空,因此它的生命周期是不稳定的。也就是说,在Android中静态变量可能随时被系统置空,变为null,其它地方在使用的时候就会产生空指针现象

在Android开发中不提倡过多使用static类型的变量(除了 static final)因为静态变量生命周期较长,而且不易被系统回收,因此如果不能合理地使用静态变量,就会适得其反,造成大量的内存浪费,所谓过犹不及。
经过我的多方查证 建议在具备下列全部条件的情况下,尽量使用静态变量:
(1) 变量所包含的对象体积较大,占用内存较多。
(2) 变量所包含的对象生命周期较长。
(3) 变量所包含的对象数据稳定。
(4) 该类的对象实例有对该变量所包含的对象的共享需求。
如果变量不具备上述特点建议你不要轻易地使用静态变量,以免弄巧成拙。
对于全局变量使用Android提供了 Application 其生命周期与应用程序共存亡。所以对于全局变量可以写在 Application。

到底使用哪一种存储方式?

(1) 如果是简单的数据结构,首选 SharedPreferences
(2) 如果是数据量大处理复杂的话,首选是sql数据库 对于结构化的数据,一定要使用数据库,虽然会显得比较麻烦,但是后续的使用中会获益无穷
(3) 普通文件就是指文本文件,二进制文件,多媒体文件,还有频繁的读取要是用二进制文件。
(4) 使用网络存储时要避免传输大数据量数据,应注意对网络传输方式的优化(减少请求次数等)。

文件存储方式(实战工具类)

文件存储方式工具类

数据库存储方式(实战工具类)

数据库最近学会的是一个DAO 简直爱死这个了,处理数据库数据是真的轻松。

示例:

  public class DbController {

    /**
     * Helper
     */
    private DaoMaster.DevOpenHelper mHelper;
    /**
     * 数据库
     */
    private SQLiteDatabase db;
    /**
     * DaoMaster
     */
    private DaoMaster mDaoMaster;
    /**
     * DaoSession
     */
    private DaoSession mDaoSession;
    /**
     * 上下文
     */
    private Context context;

    private static DbController mDbController;

    /**
     * dao
     */
    private StudentsDao studentsDao;


    /**
     * 获取单例
     */
    public static DbController getInstance(Context context) {
        if (mDbController == null) {
            synchronized (DbController.class) {
                if (mDbController == null) {
                    mDbController = new DbController(context);
                }
            }
        }
        return mDbController;
    }


    /**
     * 初始化
     *
     * @param context
     */
    public DbController(Context context) {
        this.context = context;
        mHelper = new DaoMaster.DevOpenHelper(context, "person.db", null);
        mDaoMaster = new DaoMaster(getWritableDatabase());
        mDaoSession = mDaoMaster.newSession();
        studentsDao = mDaoSession.getStudentsDao();
        //  diningRoomDao = mDaoSession.getDiningRoomDao();


    }


    /**
     * 获取可写数据库
     *
     * @return
     */
    private SQLiteDatabase getWritableDatabase() {
        if (mHelper == null) {
            mHelper = new DaoMaster.DevOpenHelper(context, "person.db", null);
        }
        SQLiteDatabase db = mHelper.getWritableDatabase();
        return db;
    }

    public boolean execSQL(String sql) {
        if (db == null) {
            db = getWritableDatabase();
        }
        try {
            db.execSQL(sql);
            return true;
        } catch (SQLException s) {
            Log.e("SQLException", s.getMessage());
            return false;
        }
    }

    /**
     * 插入学生数据
     *
     * @param
     */
    public void insertStudents(Students studentsData) {
        studentsDao.insertOrReplace(studentsData);
    }


    /**
     * 批量插入学生数据
     */
    public void saveStudentLists(final List<StudentBean> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        studentsDao.getSession().runInTx(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < list.size(); i++) {
                    Students studentsData = new Students();
                    studentsData.setLast_change_id(list.get(i).getLast_change_id());
                    studentsData.setClass_name(list.get(i).getClass_name());
                    studentsDao.insertOrReplace(studentsData);

                }
            }
        });

    }


    /**
     * 修改学生信息
     *
     * @param studentsData 学生信息
     */
    public void upDateStudents(Students studentsData) {
        studentsDao.update(studentsData);
    }

    /**
     * 查询所有学生数据
     */
    public List<Students> searchAllStudents() {
        List<Students> list = studentsDao.queryBuilder().list();
        return list;
    }

    /**
     * 按条件查询数据学生信息
     */
    public Students searchStudentsByID(int user_id) {
        Students studentsData = studentsDao.queryBuilder().where(StudentsDao.Properties.Id.eq(user_id)).build().unique();
        return studentsData;
    }

    /**
     * 按条件查询卡号
     */
    public Students searchStudentsByCard(String card) {
        Students studentsData = studentsDao.queryBuilder().where(StudentsDao.Properties.Real_number.eq(card)).build().unique();
        return studentsData;
    }

    /**
     * 删除学生数据
     */
    public void delete(String userId) {
        studentsDao.queryBuilder().where(StudentsDao.Properties.Id.eq(userId)).buildDelete().executeDeleteWithoutDetachingEntities();
    }

    /**
     * 清理所有学生数据
     */
    public void deleteStudentData() {
        studentsDao.deleteAll();
    }

}

每天进步一点点。。。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/2812.html原文链接:https://javaforall.net

(1)
上一篇 2021年3月12日 下午10:52
下一篇 2021年3月12日 下午10:52


相关推荐

  • LAMP环境跟LNMP环境有什么不同,主要用什么地方

    LAMP环境跟LNMP环境有什么不同,主要用什么地方

    2021年9月24日
    48
  • RSA加密的原理

    RSA加密的原理一 RSA 加密简介 RSA 加密是一种非对称加密 可以在不直接传递密钥的情况下 完成解密 这能够确保信息的安全性 避免了直接传递密钥所造成的被激活成功教程的风险 是由一对密钥来进行加解密的过程 分别称为公钥和私钥 两者之间有数学相关 该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性 通常个人保存私钥 公钥是公开的 可能同时多人持有 二 RSA 加密 签名区别加密和签名都是为了安全性考虑 但略有不同 常有人问加密和签名是用私钥还是公钥 其实都是对加密和签名的作用有所混淆 简单的说 加密是为了防

    2026年3月26日
    3
  • 【转载】第四章、架构设计

    【转载】第四章、架构设计

    2021年8月15日
    59
  • Pycharm使用技巧——自动调整代码格式汇总!自动化神器!

    Pycharm使用技巧——自动调整代码格式汇总!自动化神器!代码自动填充了空格问题在使用pycharm的代码编辑器时,常常懒得写空格,如下图,但这是不符合代码规范的,而且也会影响可读性。解决方法pycharm有自动调整代码格式的快捷键,默认为Alt+Ctrl+L,按下快捷键后,代码自动填充了空格。自动对齐代码问题在使用pycharm的代码编辑器时,有点时候copy的代码的没有按照代码格式对齐,如下图,但这是不符合代码规范的,而且也会影响可读性。解决方法pycharm有自动调整代码格式的快捷键,默认为Alt+Ctrl+L

    2022年8月27日
    28
  • Django(33)Django操作cookie

    Django(33)Django操作cookie前言cookie:在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录

    2022年7月29日
    9
  • MCDEX 与 Celer cBridge 达成合作,将更多用户带向以太坊二层

    MCDEX 与 Celer cBridge 达成合作,将更多用户带向以太坊二层我们很高兴地宣布,MCDEX已与Celer达成合作并集成了cBridge,让用户能够以更低的成本和延迟在部署于Arbitrumrollup上的MCDEX中桥接来自其他一层链和以太坊二层的资产。CelercBridge还允许MCDEX用户跳过Arbitrum的7天等待期,以提高DeFi流动性及交易效率,进一步推动对MCDEX的采用。用户现可通过MCDEX上的集成链接访问cBridge。此外,cBridge还将支持MCDEX的治理代币MCB从Arbitrum到以太坊的跨链快速提…

    2022年5月5日
    55

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号