Android 数据存储方案

用DataStore全面替代SharedPreferences,掌握安卓数据存储终极方案 谷歌推出的DataStore库革新了安卓轻量级数据存储方案,解决了SharedPreferences的阻塞、数据丢失和类型安全缺陷。DataStore通过事务性设计、异步流式API和ProtoBuf支持,提供原子操作、多进程兼容及复杂数据类型处理。文章对比Preferences与ProtoDataStore两种模式,详解初始化、迁移和性能优化策略,并给出用户配置中心的完整实现案例。DataStore兼容Java项目,面试常见问题解析进一步展示其技术优势,成为替代传统SP的理想选择。 阅读详情

       我们每天都在和数据打交道,在编写应程序以及使用应用程序的过程中时时刻刻存在着数据之间的交互,平时我们上 QQ、微信、微博,其实都是在产生数据,为了使关机后数据不丢失,我们就需要数据的持久化,这里简单的说一下数据的持久化,数据的持久化其实就是将那些在内存中的瞬时数据保存到存储设备中,保证即使在设备关机的情况下这些数据任然不会丢失,保存到内存中的数据是处于瞬时状态的,而保存在存储设备中的的数据是处于持久化状态的,持久化技术则是提供了一种解决数据持久化的机制,而我们今天要讨论的是 Android 的数据持久化技术,Android 系统主要提供了 3 种方式用于实现简单的数据持久化功能:如下



       上面就是我们 Android 系统提供的数据存储方案,另外我们也可以存放在我们手机的 SD 卡中,但可能相对来说不是太安全,下面我们具体来一一分析这些数据的存储方式


一、文件存储


       文件存储是 Android 中最基本的一种数据存储方式,它不对内容进行任何的格式化处理,所有数据都是原封不动的保存到文件当中,因此文件存储比较适合于存出一些二进制和简单的文本数据,对于较为复杂的数据存储则不方便,需要自定义一套自己的格式规范,以便之后从文件中解析

当文件被保存在内部存储中时,默认情况下,文件是应用私有的,其它应用不能访问,当用户卸载应用时,这些文件才能被删除

文件默认的存储位置:/data/data/包名/files/文件名


1.将数据存储到文件中


Context 类中提供了一个 openFileOutput() 方法,可以用于将数据存储到指定的文件夹中,默认的存储位置:/data/data/包名/files/文件名,以下是代码示例:

public void save(String inputData) {
    FileOutputStream out = null;
    BufferedWriter writer = null;
    try {
        out = openFileOutput("data", Context.MODE_PRIVATE); 
        writer = new BufferedWriter(new OutputStreamWriter(out));
        writer.write(inputData);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (writer != null) {
                writer.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我们对上面的代码进行简单的分析,调用 Context 的 openFileOutput() 方法,从上面我们可以看到 openFileOutput() 方法接受两个参数,它会返回给一个 FileOutputStream 对象:

1.1 第一个参数是文件名,也就是文件在创建的时候的文件名,需要注意的是这里指定的文件名不可以包含路径(不能包含路径分隔符 “/” ,如果文件不存在,Android 会自动创建它),因为所有的文件都是默认的存储位置:/data/data/包名/files/目录下的,

1.2 第二个参数是用于指定文件的操作模式,分为 4 种


1)context.MODE_PRIVATE:

是默认的操作模式,代表该文件是私有数据,在该模式下,写入的内容会覆盖原文件的内容

2)context.MODE_APPEND:

则表示如果该文件已经存在,就往文件里面追加内容,否则就创建新文件

3)context.MODE_READABLE:

表示当前文件可以被其他应用读取

4)context.MODE_WORLD_WRITEABLE:

表示当前文件可以被其他应用写入

这里需要注意的是由于 3)4)这两种模式允许其他应用程序对我们应用程序中的文件进行读写操作,所以很容易引起安全性漏洞,已经在 Android 4.2 版本中废弃

总结一下主要分为 3 步:

1)调用 Context 的 openFileOutput() 方法,填入文件名和操作模式,返回 FileOutputStream 对象

2)通多 FileOutputStream 对象的 write() 方法写入数据

3)通过 FileOutputStream 对象的 close() 方法关闭数据流


2.从文件中读取数据


Context 类提供了 openFileInput() 方法,用于从文件中读取数据,示例代码如下:

public String load() {
    FileInputStream in = null;
    BufferedReader reader = null;
    StringBuilder content = new StringBuilder();
    try {
        in = openFileInput("data");
        reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while ((line = reader.readLine()) != null) {
            content.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return content.toString();
}

       同上我们也来简单的分析一下这段代码,在这段代码中,首先通过调用 openFileInput() 方法,获取到 FileInputStream 对象,然后借助它又构建出一个 InputStreamReader 对象,接着再使用 InputStreamReader 对象构建出一个 BufferedReader 对象,这样就能通过 BufferedReader 进行一行一行的读取,把文件中的文本内容全部读取出来,并存放在一个 StringBuilder 对象中,最后读取到的内容返回就可以了,总结如下:

1)调用 openFileInput() 方法,参数中填入文件名,返回 FileInputStream 对象

2)调用 Java 流对象的 read() 方法读取字节

3)调用 Java 流对象的 close() 方法关闭流

到这里我们就已经把文件存储方面的知识学习完了,最后我们来回顾一下,其实所用到的核心技术就是 Context 类中提供的 openFileInput() 和 openFileOutput() 方法,之后就是用到 Java 流的方式来进行读写操作,不过文件存储方式并不适合存储一些比较复杂的数据,因此接下来我们学习 Android 中的另一种数据持久化方式,它比文件存储更加简单易用,而且对某些指定的数据进行读写操作更加方便,如下



二、SharedPreferences存储


      不同于文件的存储方式,SharedPreferences 是通过键值对的方式来存储数据的,也就是说当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通多这个键把相应的值取出来,而且 SharedPreferences 还支持不同数据类型的存储,如果存储的数据类型是整型,那么读取出来的数据也是整型的,如果存储的是字符串,那么读取出来的数据仍然是字符串,这里我们就能明显的感觉到使用 SharedPreferences 来进行数据持久化技术比文件存储更加方便


1.将数据存储到 SharedPreferences 中


要想使用 SharedPreferences 存储数据,首先要获取到 SharedPreferences 对象,Android 中主要提供了 3 种方法用于得到 SharedPreferences 对象:


1)Context 类中的 getSharedPreferences() 方法


这个方法接受两个参数,第一个参数用于指定 SharedPreferences 的文件名称,如果指定的文件不存在则会创建一个,SharedPreferences 文件都是存放在/data/data/包名/shared_prefs/目录下的,第二个参数则用于指定操作模式,目前只有 MODE_PRIVATE 这一种模式可选,是默认的操作模式,和直接传入 0 效果是一样的,表示只有当前应用程序才可以对这个 SharedPreferences 文件进行读写,其他几种方式已经都被废弃 


2)Activity 类中的 getPreferences() 方法


这个方法和 Context 类中的 getSharedPreferences() 方法很相似,不过它只接受一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为 SharedPreferences 的文件名


3)PreferenceManager 类中 getDefaultSharedPreferences() 方法


这是一个静态方法,它接受一个 Context 参数,并自动使用当前应用程序的包名作为前缀来命名 SharedPreferences 文件,得到了 SharedPreferences 对象之后,就可以开始向 SharedPreferences 文件中存储数据了,代码如下:

// SharedPreferences 调用 edit() 方法即获取 Editor 对象
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("name", "USER_NAME");
editor.putInt("age", 25);
editor.apply(); // 

可以看到主要分为 3 个步骤来实现

第一、调用 SharedPreferences 对象的 edit() 方法来获取 SharedPreferences.Editor 对象


第二、向 SharedPreferences.Editor 对象中添加数据,比如添加一个布尔类型的数据就使用 putBoolean() 方法,添加一个字符串则使用 putString() 方法,依次类推


第三、调用 apply() 方法将添加的数据提交,从而完成数据存储操作


除此之外,Editor 对象还包含clear()和remove()等方法


2.从 SharedPreferences 中读取数据


相对于 SharedPreferences 存储数据则从 SharedPreferences 中读取数据则更加简单,SharedPreferences 对象中提供了一系列的 get 方法,用于对存储数据进行读取,每种方法都对应了 SharedPreferences.Editor 中的一种 put 方法,比如读取一个布尔类型的数据就使用 getBoolean() 方法,读取一个字符串就是用 getString() 方法,这些 get 方法都接受两个参数,第一个参数是键,传入存储数据时使用的键就可以得到相应的值了,第二个参数是默认值,即表示当传入的键找不到对应的值时会以什么样的默认值进行返回,示例代码如下:

SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);
String name = pref.getString("name", "");
int age = pref.getInt("age", 0);

到这里关于 SharedPreferences 的内容我们就学习完毕了,接下来我们要学习最重要的持久化技术,Android 中的数据库技术



三、SQLite 数据库存储


我们在前面学习了文件存储和SharedPreferences存储,但这些毕竟都属于保存一些简单的数据和键值对,当需要存储大量复杂的关系型数据的时候,上面的两种就不是那么的得心应手了,SQLite 是一款轻量级的关系型数据库,它的运算速度快,占用资源少,同长只需要几百 KB 的内存就够了,因而特别适合在移动设备上使用,SQLite 不仅支持标准的 SQL 语法,还遵循了数据库的 ACID 事务,所以只要你以前使用过其他关系型数据库,就可以很快地上手使用 SQLite,Android 正是把这个极为强大的数据库嵌入到系统当中,使得本地化功能有了质的飞跃


1.创建数据库


Android 为了让我们更加方便的管理数据库,专门提供了一个 SQLiteOpenHelper 帮组类,借助这个类就可以非常简单的对数据库进行创建和升级,首先 SQLiteOpenHelper 是一个抽象类,这就是说,我们如果使用它,就需要创建一个自己的帮助类去继承它,SQLiteOpenHelper 中有两个抽象方法,分别是 onCreat() 和 onUpgrade(),我们必须在自己的帮助类中重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑


SQLiteOpenHelper 中还有两个重要的方法: getReadableDatabase() 和 getWritableDatabase() 方法这两个方法都可以创建或打开一个现有的数据库(如果数据库存在则直接打开,否则创建一个新的数据库)并返回一个可对数据库进行读写操作的对象,不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase() 方法返回的对象将以读的方式去打开数据库,而 getWritableDatabase() 方法将出现异常


另外 SQLiteOpenHelper 中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可,这个方法接受 4 个参数,第一个参是 Context,第二个参数是数据库名,创建数据库的时候就是这里指定的名称,第三个参数容许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null,第四个参数表示当前数据库的版本号,可以对数据库进行升级操作,构建出 SQLiteOpenHelper 的实例以后,再掉用 getReadableDatabase() 和 getWritableDatabase() 方法就能创建数据库了,数据库文件会存放在/data/data/包名/databases/目录下,此时从写 onCreate() 方法也会得到执行,所以通长会在这里去处理一些创建表的逻辑

这里我们新建 MyDatabaseHelper 继承自 SQLiteOpenHelper,代码如下:

/**
 * MyDatabaseHelper 帮助类
 */

public class MyDatabaseHelper extends SQLiteOpenHelper {

    /**
     * text 表示文本类型,integer 表示整型
     * primary key 表示将 id 设为主键,并用 autoincrement 键字表示 id 是自增长的
     */
    private static final String CREATE_BOOK = "create table book(" +
            "id integer primary key autoincrement," +
            "name text," +
            "pages integer)";

    private Context mContext;

    /**
     * 构造方法
     *
     * @param context 上下文
     * @param name    数据库名,创建数据库时使用的就是这里的名称
     * @param factory 允许我们在查询数据时返回一个自定义的Cursor,一般传入null
     * @param version 数据库版本号
     */
    public MyDatabaseHelper(Context context, String name,
                            SQLiteDatabase.CursorFactory factory,
                            int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    /**
     * 创建数据库
     *
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
    }

    /**
     * 升级数据库
     *
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}



接下来我们就可以在应用程序中创建数据库了,代码如下:

MyDatabaseHelper dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
dbHelper.getWritableDatabase();

这里我们构建了一个 MyDatabaseHelper 对象,并且通过构造函数的参数将数据库名指定为 BookStore.db,版本号指定为 1,并调用 getWritableDatabase() 方法,这样数据库也就得到了创建


2.升级数据库


细心的人估计已经注意到了,下面的这个方法我们还没有用:

    /**
     * 升级数据库
     *
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
升级数据库只需要将版本号增加,然后执行 onUpgrade() 方法就可以了


3. SQLite 数据库的增删改查


现在我们已经学习了创建和升级数据库的方法,接下来我们来一起学习下如何对表中的数据进行操作,其实我们可以对数据进行的操作也就 4 种,即 CRUD 


C  Create   添加  insert
R  Retrieve 查询  select
U  Update   更新  update
D  Delete   删除  delete

首先创建数据库表的实体类BookBean:

/**
 * Book 实体类
 */

public class BookBean {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    private int pages;

}


前面我们已经知道,调用 SQLiteOpenHelper 的 getReadableDatabase() 和 getWritableDatabase() 方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个  SQLiteDatabase 对象,借助这儿对象就可以对数据库进行 CRUD 操作了

SQLiteDatabase db = dbHelper.getWritableDatabase();

接下来将数据库 book 表的增删改查封装起来,如下:

/**
 * Book 表
 */

public class Book {
    private MyDatabaseHelper dbHelper;
    public Book(Context context){
        dbHelper = new MyDatabaseHelper(context, "BookStore.db", null, 1);
    }

    /**
     * 增
     */
    public boolean add(BookBean bean){
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name", bean.getName());
        values.put("pages", bean.getPages());
        /**
         * table: 表名
         * null: 一般传null
         * values: 表中添加的一行的数据内容, ContentValues以Map封装
         */
        long result = db.insert("book", "null", values); // 内部在拼装sql语句
        // 关闭数据库
        db.close();
        if (result == -1) {
            return false;
        }
        return true;
    }

    /**
     * 删
     */
    public int delete(String name){
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        /**
         * table: 表名
         * whereClause: 删除条件
         * whereArgs: 删除条件占位符的参数
         * 返回值是: 成功删除了多少行
         */
        int result = db.delete("book", "name = ?", new String[]{name});
        // 关闭数据库
        db.close();
        return result;
    }

    /**
     * 改
     */
    public int update(BookBean bean){
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        /**
         * table: 表名
         * values: 更改字段的内容, 以map封装
         * whereClause: 更新条件
         * whereArgs: 更新条件占位符的参数
         * sql: update person set pages='10' where name='jianai';
         */
        ContentValues values = new ContentValues();
        values.put("pages", bean.getPages());
        // 返回的值: 成功修改了多少行
        int result = db.update("book", values, "name = ?", new String[]{bean.getName()});
        // 关闭数据库
        db.close();
        return result;
    }

    /**
     * 查
     */
    public BookBean query(String name){
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        BookBean bean = new BookBean();
        /**
         * table: 指定查询的表名
         * columns: 指定查询的列名(null:查询所有)
         * selection: 指定 where 的约束条件
         * selectionArgs: 为 where 中的占位符提供具体的值
         * groupBy: 指定需要 group by 的列
         * having: 对 group by 后的结果进一步约束
         * orderBy: 指定查询结果的排序方式
         */
        Cursor cursor = db.query("book", new String[]{"id","name","pages"}, "name  = ?",
                new String[] {name}, null, null, "id desc");
        /**
         * 判断结果集中是否有数据
         */
        if(cursor != null && cursor.getCount() >0){
            // 循环遍历结果集获取结果集的内容
            while(cursor.moveToNext()){
                // 获取这一行上所有的数据内容
                int id = cursor.getInt(0);
                bean.setName(cursor.getString(1));
                bean.setPages(Integer.parseInt(cursor.getString(2)));
            }
        }

        // 关闭数据库
        db.close();
        return bean;
    }
}


到这里我们就可以通过创建 Book 的实例,调用该实例的方法来增删改查数据库 book 表了:

Book book = new Book(context);
// 增
BookBean bean = new BookBean();
bean.setName("jianai");
bean.setPages("15");
book.add(bean);
// 删
book.delete("jianai");
// 改
BookBean bean = new BookBean();
bean.setName("jianai");
bean.setPages("40");
book.update(bean);
// 查
BookBean bean = book.query("lisi");

使用 SQL 语句操作数据库

首先打开数据库对应的对象:

MyDatabaseHelper dbHelper = new MyDatabaseHelper(context, "BookStore.db", null, 1);
SQLiteDatabase db = dbHelper.getWritableDatabase();

然后我们就可以直接使用 SQL 语句操作数据库:

增  db.execSQL("insert into book (name ,pages) values (?, ?)",new String[]{"gangtie","30"});
删  db.execSQL("delete from book where pages>?",new String[]{"200"});
改  db.execSQL("update person set pages=? where name=?",new String[]{"20","wangwu"});
查  db.rawQuery("select * from book",null);

到这里我们就把 SQLite 数据库学习完了,其实在真正的项目实际开发中我们通常也使用很多第三方的数据库,大家可以根据自己的喜好自行选择




Cadence Orcad Capture原理图断线的检查与避免方法 在设计电路图中,尤其是直接借鉴别人的设计进行二次开发的过程中难免会遇到如下尴尬的情况。有没有眼神好的朋友发现图纸的哪里有不对劲的地方呢? 阅读详情

相关推荐

数字图像处理第九章笔记

目录一、腐蚀与膨胀1、腐蚀2、膨胀3、对偶性4、开操作与闭操作二、一些基本的形态学算法1、边界提取2、孔洞填充3、连通分量提取4、凸壳5、细化6、粗化7、骨架8、形态学重建三、灰度级形态学1、腐蚀和膨胀2、开运算和闭运算3、灰度级形态学算法 一、腐蚀与膨胀 1、腐蚀 腐蚀可以去除图像的某些部分。 2、膨胀 膨胀可以连接裂缝。 3、对偶性 膨胀和腐蚀彼此关于集合求补运算和反射运算是对偶的 4、开操作与闭操作 开操作:B对A先腐蚀,再进行膨胀 可以平滑物体轮廓,断开较窄的狭颈并消除较细的突出物。 闭操作

方悔读书迟 1375

Android存储路径大全

Android的存储路径实际分类为1)内部存储路径2)内部缓存存储路径3)外部存储路径4)外部缓存存储路径在有些手机上,系统也会在内部划出一个内部的SDCard路径和内部存储路径,所以当有SDCard的时候,就会有6个路径存在了那么存储路径和缓存存储路径的区别就是:1、缓存路径一般用于存放一些缓存数据,当程序删除的时候,缓存文件夹也会随之删除,避免了程序在卸载之后残留大量文件。

顺其自然~专栏 3629

数值计算方法 matlab用二分法或简单迭代法求_快速求解方程的根——二分法与牛顿迭代法

今天是周四高等数学专题的第7篇文章。之前的文章和大家聊了许多数学上的理论,今天和大家聊点有用的东西。我们都知道,工业上的很多问题经过抽象和建模之后,本质还是数学问题。而说到数学问题就离不开方程,在数学上我们可以用各种推算、公式,但是有没有想过在计算机领域我们如何解一个比较复杂的方程?如果之前没有想过,那你可能得想一想,因为以后很有可能会在面试题当中遇到。二分法我们要介绍的第一个方法是二分法。说到二...

weixin_39945915的博客 1304

彻底搞懂Android文件存储---内部存储,外部存储以及各种存储路径解惑

彻底搞懂Android文件存储---内部存储,外部存储以及各种存储路径解惑 1、Android中内部存储,外部存储的概念 2、清除数据和清除缓存到底清除了什么数据 3、/storage/sdcard,/sdcard,/mnt/sdcard,/storage/emulated/0之间的关系 4、一张图看懂Ram,Rom,以及扩展存储(TF卡)的区别;内部存储,外部存储的区别。

雨季莫忧离的博客 11万+

win2012没有远程桌面授权服务器可以提供许可证 如何远程

如果远程windows服务器时,提示“没有远程桌面授权服务器可以提供许可证 如何远程”,先通过以下方式进行强制登录,然后在对服务器进行设置即可,延期使用。 强制登录服务器方式; 1、运行—输入:mstsc /admin /v ip:端口 回车即可 2、进入远程桌面,输入 ip:端口 /admin 例如:mstsc /admin /v 192.168.0.131:23568 进入服务器以后,按照以下步骤进行设置即可: ...

蜗牛快爬 1万+

PSINS工具箱学习(四)捷联惯导更新算法

原始 Markdown文档、Visio流程图、XMind思维导图见:https://github.com/LiZhengXiao99/Navigation-Learning。

实践出真理,接毕设/课设项目开发指导 607

Android 文件存储位置梳理

所有的安卓设备都有外部存储和内部存储,这两个名称来源于安卓的早期设备,那个时候的设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。 在后来的设备中,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal" 和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储(外部存储)。 ...

u010227042的博客 9352

DCMM评估报告模板样例

这篇DCMM评估报告对某数据管理公司2020年的数据管理能力进行了全面分析。报告显示,该公司在数据战略方面取得初步进展,但在数据治理和数据架构方面仍存在明显不足,包括缺乏有效治理流程、数据质量监控不足,以及数据标准化和转换灵活性不足等问题。评估报告提出了针对性改进建议,包括完善数据战略、建立治理流程、加强质量监控和提升数据转换灵活性等,为提升数据管理成熟度提供了重要指导。

cdfunlove的博客 166

Android各种存储路径详解

转载自:https://blog.youkuaiyun.com/s13383754499/article/details/82910704

cxjwpp的博客 323

OpenCV实战(1)——OpenCV与图像处理基础

OpenCV 是一个跨平台计算机视觉和机器学习库,实现了图像处理和计算机视觉方面的很多通用算法。本节将介绍 OpenCV 的基础知识,以及如何编译运行 OpenCV 程序,并介绍如何完成最基本的图像处理任务——读取、显示和保存图像。除此之外,鼠标事件和图形绘制也是 OpenCV 计算机视觉项目中常用的基本功能,本节介绍了如何使用这两个重要的 OpenCV 功能。

盼小辉丶的博客 12万+

NSIS教程(8): 基于第三方界面库的安装包界面

前面的几篇文章介绍了NSIS的传统界面的安装包和现代界面的安装包的制作方法,也提到了NSIS支持自定义页面(即使用page custom)的特性,自定义页面需要用户自己创建对话框、控件、添加控件响应等等,虽然NSIS提供了nsDialogs.nsh来支持这些功能,但使用起来还是不太方便(需要专门了解这个插件诸多用法),而且不够灵活,所以本文介绍一种终极的自定义界面的安装包解决方案,即完全使用第三方

while(1) { smile(); } 9万+

Android文件操作,数据读写,数据存储,存储路径,一篇全部搞定

得学会写博客,以前是觉得逼格,现在发现是为了总结自己的所学,项目做完了不代表会了,东西学完了不代表懂了。总结之后不会、不懂也无所谓,自己的接口调了就行了。当然了,啪啦啪啦,写完做完还不会的,我也不想说什么。看完这篇不会,下次就直接调我的接口吧。代码已经上传到 github上面去了,网址:https://github.com/KEYD111/AndroidFileOperation ...

dadachenchen的博客 1万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

android 存储策略,安卓数据存储方案

持久化技术简介数据持久化就是指将那些内存中的瞬时数据保存在存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不回丢失。保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,持久化技术则提供一种机制可以让数据在瞬时状态和持久状态之间进行转换。Android 系统中主要提供了3种方式,即文件存储、SharedPreference 存储以及数据存储。1、文件存储文件存储是...

weixin_29864831的博客 374

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

探索 LeanStorageDemo-Android:一款强大的安卓数据存储解决方案

探索 LeanStorageDemo-Android:一款强大的安卓数据存储解决方案 在快速发展的移动应用领域,高效、可靠的数据管理是应用程序成功的关键因素之一。今天我们要介绍的是 LeanStorageDemo-Android,一个由 LeanCloud 开发的安卓示例应用,它展示了如何利用 LeanCloud 的 LeanStorage 服务进行数据存储和检索。这款项目不仅提供了清晰的代码示例...

gitblog_00040的博客 651

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Android的数据存储方案

1、概述 android中的数据是有权限控制的,应用软件数据为该应用软件所私有的。但是android也提供了一种标准的方式将软件的私有数据开放给其他应用软件。 android可供选择的存储方式:sharedPreferences、文件存储、SQLite数据库方式、内容提供器(Content provider)和网络存储。 2、sharedPreferences sharedPrefer

心无所属的专栏 1183

[安卓课内笔记]数据存储解决方案

一、文件存储 使用IO流操作文件 二、SharedPreferences存储 使用键值对的方式来存储数据 数据存储在:工作目录/data/data/项目包名/shared_prefs/目录下 使用下方封装的工具类进行操作 public class DataHelper { /** * SharedPreferences方式存储 * @param context XML的文件名,通常取模块名 * @param key 存储在XML中的key *

qq_44748994的博客 233

Android数据存储方案初探

本文是笔者在阅读郭霖老师《第一行代码》数据存储全方案这一章的总结。书上介绍的数据存储的方式有这几种: 1.文件存储, 2.SharedPreference存储, 3.SQLite数据库存储 一、文件存储 描述:将要存储的数据原封不动地保存到文件当中,所以只适合存储一些简单的文件数据或二进制数据。 文件默认存储到/data/data/<p...

weixin_30361641的博客 104

DataStore Codelab - Android 数据存储解决方案

DataStore Codelab - Android 数据存储解决方案 1. 项目基础介绍 DataStore Codelab 是由 Android 开源项目提供的一个示例项目,旨在帮助开发者理解并使用 Android 的 DataStore。DataStore 是一种新的、改进的数据存储解决方案,旨在替代传统的 SharedPreferences。该项目主要使用 Kotlin 语言编写,完全兼...

gitblog_00470的博客 439

每日面试题-Android 持久化数据存储方案有哪些?

基于XML文件,仅支持基本数据类型(String/Int/Boolean等):异步/响应式数据存储(Kotlin协程 + Flow支持):简单配置项、用户偏好设置等小数据量存储。:非结构化数据(文本、图片、音视频等):结构化数据存储(复杂查询、事务支持):跨应用数据共享(如通讯录、媒体库):通过URI机制实现数据访问,需配合。(Jetpack组件)

weixin_45422672的博客 558

解读Android之数据存储方案

Android提供了一些永久保存数据的方法,可以根据具体的需求决定使用哪种方式存储,例如私有数据,外部程序是否可以访问等等。有以下几种方法存储:Shared Preferences;Internal Storage;External Storage;SQLite Database;Network Connection。

sywyg 5万+

android学习之 数据存储全方案

持久化数据 概念:将瞬时数据保存下来 文件存储 不对文件进行任何格式化处理,适合简单或二进制文件 openFileInput() 以文件名作为唯一参数,自动到data/data//file目录下加载文件,得到FileInputStream对象,通过java流读出来 SharedPreferences 通过键值对储存,且储存类型多样 得到对象的三种方式 Context 中的 getSharedPreferences(文件名,MODE_PRIVATE) Activity 中的 getPrefere

weixin_51518489的博客 1616

Cloudant Sync - Android 数据存储常见问题解决方案

Cloudant Sync - Android 数据存储常见问题解决方案 项目基础介绍 Cloudant Sync 是一个基于 JSON 的文档数据存储库,专为 Android 应用设计。它允许应用程序在设备上存储、索引和查询本地 JSON 数据,并可以同步多个设备之间的数据。Cloudant Sync 采用 Apache CouchDB 的复制协议,为不想或不需要运行完整 CouchDB 实例的...

gitblog_01154的博客 959

Android Learning:数据存储方案归纳与总结

前言   最近在学习《第一行android代码》和《疯狂android讲义》,我的感触是Android应用的本质其实就是数据的处理,包括数据的接收,存储,处理以及显示,我想针对这几环分别写一篇博客,记得我的学习心得,也希望跟各位新手同学相互努力促进。今天这篇博客,我想介绍一下数据的存储,因为数据的接收,存储,处理以及显示这几环环环相扣,而数据的存储直接关系到数据的处理和显示,所以显得尤为重...

weixin_30655569的博客 124

安卓官方建议的数据存储的可选方案

http://developer.android.com/guide/topics/data/data-storage.html

willcomes的博客 495

Android数据存储方案

文件存储 Context类中提供了一个openFileOutput()方法,可以用于将数据存储到指定文件中。第一个参数是文件名第二个参数是文件的操作模式 文件默认会存储到/data/data/package name/files/目录下 MainActivity.java package com.zhoujian.persistentdata; import android.content.Co...

weixin_34177064的博客 139

安卓中轻量级数据存储方案分析探讨

MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今在微信上使用,其性能和稳定性经过了时间的验证。近期也已移植到 Android / macOS / Win32 / POSIX 平台,一并开源。存储1000个int类型的数据所占空间:mmkv:16KB存储1000个String类型的数据所占空间:mmkv:32KB如果你有多进程支持的需求,MMKV是唯一的选择。

高级程序猿一枚,多年前后端经验。记录分享遇到问题,了解最新知识。 991
上一篇: Android View 基础知识
下一篇: Android 什么是 Material Design
QDJdeveloper
博客等级 码龄11年 108粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值