Android 缓存设计与实现方式

您所在的位置:网站首页 安卓缓存数据在哪里 Android 缓存设计与实现方式

Android 缓存设计与实现方式

#Android 缓存设计与实现方式| 来源: 网络整理| 查看: 265

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

Android 缓存设计与实现方式

在初级面试中经常遇到四大组件、五大存储、六大布局。该篇文章主要分析下Android中实现缓存的方式。

一、了解Android的存储方式

关于五大存储

大家一般期待的回答是下面这样的。

SharedPreferences SQLite数据库 ContentProvider(内容提供者) 文件存储 网络存储

还可以用另外一种方式区分,远端存储,和本地存储。

SharedPreferences

存储目录:/data/data//shared_prefs/ 轻量级存储,本地目录在,在正式发布的版本上,只有root才能看到。

什么是轻量? 对其环境依赖的越少,就越轻量,也就是减少耦合的意思。

SQLite

存储目录:/data/data//databases/ SQLite 是一个微型数据库,效率高,特别适合存储结构化的数据。Android 中内置了SQLite数据库,它支持SQL语法,但在Android中一般不直接写SQL语句,而是使用第三方库操作对象,达到对数据库增删改查的目的,比如 GreenDao。

ContentProvider

ContentProvider 是Android存储数据的方案,底部仍然是使用SqLite。它根据Uri(Universal Resource Identifier)统一资源定位符 确定资源。可以多app使用,比如通讯录可以给多个应用获取。虽然日常开发中对 ContentProvider 使用不多,但和ContentProvider的接触却很频繁,比如 选择一张图片,我们首先拿到的却是Uri。

文件存储

文件存储,分为内部存储和外部存储。

怎么区分内部存储和外部存储?

对用户而言可插拔的SD卡就是外部存储,焊接在手机内部的就是内部存储。

但对于开发者而言并不是这样。

在该应用目录下的存储是内部存储。

反之即使存在手机不可拆卸的存储卡上,也叫外部存储。

内部存储和外部存储有哪些不同?

(1) 在/data/data/package_name目录下,在debug环境下,可以通过AndroidStudio的Device File Explorer查询到该app的存储,如果需要查询其它app的这个目录,则需要Root。 (2) 内部存储在应用卸载的时候会被清除,而外部存储不会。 (3) 操作内部存储目录不需要申请存储权限,而外部存储需要存储权限。这点也能理解,操作自己的应用不需要过多干预提醒。

网络存储

文件保存在服务器上,通过url操作服务器上的资源。比如apk的版本更新下载apk的场景。

二、拓展的存储方式 GreenDao-操作对象即修改数据 ACache-一个类轻松缓存 ImageLoader/Glide-缓存图片 三、缓存设计 场景一

“我想缓存一张图片”

使用三级缓存。网络缓存(速度慢、费流量), 本地缓存,内存缓存。

首次网络加载时缓存到本地存储,缓存到内存; 当再次访问该图片时,

graph TD 再次加载该图片时 --> C{内存中是否存在} C -->|存在| D[显示图片] C -->|不存在| E{本地文件是否存在} E -->|存在| X[显示图片] E -->|不存在| F[请求网络] F --> Y[显示图片] 场景二

“我想加载新闻内容”

使用ACache 缓存新闻内容,在下次加载时先请求本地的缓存,然后后台请求网络,请求网络数据成功后再去更新页面。

graph TD A[开始] -->|start| B(加载新闻) B --> C{本地缓存是否存在} C -->|是| D[显示缓存的内容] D --> E C -->|否| E[后台请求网络数据] E -->|拿到数据| F[显示/刷新页面]

由于新闻的数据不需要与服务器保持高度统一,所以这里我们将新闻数据放入ACache中,ACache 也可以轻松的设置过期时间。

场景三

“我想在app存一万条人员信息”

当有大量数据时,如果我们把数据用JSON存在SP 或者 文件里,对单条信息的操作却要读取整个文件,这样明显是不值得的。

再看看Sqlite的有点

"适合存储结构化的数据"

那么人员信息就应该依据ID、姓名、性别、年龄等字段在Sqlite中建表。

这样在对单个数据操作时就可以通过ID进行操作。

四、GreenDao实践 明确GreenDao的核心类含义

DaoMaster: DaoMaster保存数据库对象(SQLiteDatabase)并管理特定模式的DAO类(而不是对象)。它有静态方法来创建表或删除它们。它的内部类OpenHelper和DevOpenHelper是SQLiteOpenHelper实现,它们在SQLite数据库中创建模式。

DaoSession:管理特定模式的所有可用DAO对象,您可以使用其中一个getter方法获取该对象。DaoSession还提供了一些通用的持久性方法,如实体的插入,加载,更新,刷新和删除。

XXXDao:数据访问对象(DAO)持久存在并查询实体。对于每个实体,greenDAO生成DAO。它具有比DaoSession更多的持久性方法,例如:count,loadAll和insertInTx。

Entities :可持久化对象。通常, 实体对象代表一个数据库行使用标准 Java 属性(如一个POJO 或 JavaBean )。

实践 1. 创建好输入框按钮等界面 2. 然后添加配置信息配置信息最好根据github上的地址指引去做,因为会经常保持更新。

github.com/greenrobot/…

摘:

Add the following Gradle configuration to your Android project. In your root build.gradle file: buildscript {     repositories {         jcenter()         mavenCentral() // add repository     }     dependencies {         classpath 'com.android.tools.build:gradle:3.1.1'         classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin     } } In your app modules app/build.gradle file: apply plugin: 'com.android.application' apply plugin: 'org.greenrobot.greendao' // apply plugin   dependencies {     implementation 'org.greenrobot:greendao:3.2.2' // add library }

然后在app/build.gradle 中的根目录添加greenDao的配置信息。

//数据库配置 greendao {     //数据库版本号     schemaVersion 1     //自动生成代码所在的包名     daoPackage 'com.dao.green.db'     targetGenDir 'src/main/java' } 3. 创建实体类 @Entity(nameInDb = "STUDENT") //添加该行,代表自动生成 public class Student {     @Id(autoincrement = true)     @Unique     private Long id; //主键自增长,不可重复,作为不同记录对象的标识,传入参数对象时不要传入     @Property(nameInDb = "name")     private String name; //名字     @Property(nameInDb = "mark")     private String mark; //备注

创建完成后,编译之后会自动在相应目录下生成master、session、dao文件。

4. 在自定义的Application中初始化 GreenDaopublic class App extends Application {     @Override     public void onCreate() {         super.onCreate();         //打开数据库         DbManager.getInstance().initDb(this);     } } 5. 重写MySqliteOpenHelper,防止数据库升级清空本地数据 public class MySqliteOpenHelper extends DaoMaster.DevOpenHelper {     public MySqliteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {         super(context, name, factory);     }     /**      * 需要在实体类加一个字段 或者 改变字段属性等 就需要版本更新来保存以前的数据了      *      * @param db      * @param oldVersion      * @param newVersion      */     @Override     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {         super.onUpgrade(db, oldVersion, newVersion);         //这里添加要增加的字段         MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {             @Override             public void onCreateAllTables(Database db, boolean ifNotExists) {                 DaoMaster.createAllTables(db, ifNotExists);             }             @Override             public void onDropAllTables(Database db, boolean ifExists) {                 DaoMaster.dropAllTables(db, ifExists);             }         }, StudentDao.class);     } }

MigrationHelper.java 来自github:github.com/yuweiguocn/…

6. 封装DbManager、DbHelperDbManager /**  * @author by T, Date on 2019-10-22.  * note: DB的管理类  */ public class DbManager {     //数据库名称     private static final String DATABASE_NAME = "student_data";     private static DbManager instance;     private DaoSession mDaoSession;     private DaoMaster.DevOpenHelper mDevOpenHelper;     private DaoMaster mDaoMaster;     /**      * 获取单例      *      * @return      */     public static DbManager getInstance() {         if (instance == null) {             synchronized (DbManager.class) {                 if (instance == null) {                     instance = new DbManager();                 }             }         }         return instance;     }     public void initDb(Context context) {         mDevOpenHelper = new MySqliteOpenHelper(context, DATABASE_NAME, null);         mDaoMaster = new DaoMaster(mDevOpenHelper.getWritableDatabase());         mDaoSession = mDaoMaster.newSession();         LogUtils.d("打开了数据库:" + mDevOpenHelper.getDatabaseName());     }     public DaoSession getDaoSession() {         return mDaoSession;     }     /**      * 关闭数据库 (思考:关闭数据库的场景在哪里)      */     public void closeDataBase() {         if (mDevOpenHelper != null) {             LogUtils.d("关闭了数据库" + mDevOpenHelper.getDatabaseName());         }         closeDaoSession();         closeHelper();     }     private void closeDaoSession() {         if (mDaoSession != null) {             mDaoSession.clear();             mDaoSession = null;         }     }     private void closeHelper() {         if (mDevOpenHelper != null) {             mDevOpenHelper.close();             mDevOpenHelper = null;         }     } }

DbHelper

/**  * @author by T, Date on 2019-10-22.  * note: 进一步封装,对外直接使用该类  */ public class DbHelper {     /**      * 插入一条学生信息      *      * @param student      * @return      */     public static boolean insertStudentInfo(Student student) {         if (student == null) return false;         StudentDao studentDao = DbManager.getInstance().getDaoSession().getStudentDao();         try {             long index = studentDao.insertOrReplace(student);             LogUtils.d("id:" + index);             return true;         } catch (Exception e) {             return false;         }     }     /**      * 查询所有的学生      *      * @return      */     public static List queryAllStudent() {         StudentDao studentDao = DbManager.getInstance().getDaoSession().getStudentDao();         try {             return studentDao.loadAll();         } catch (Exception e) {             return null;         }     } } 7. Activity中的使用Activity中的两个点击方法     /**      * 保存数据      *      * @param view      */     public void Save(View view) {         Student student = new Student();         student.setName(etName.getText().toString());         student.setMark(etMark.getText().toString());         boolean flag = DbHelper.insertStudentInfo(student);         LogUtils.d("插入是否成功:" + flag);     }     /**      * 查询全部数据      *      * @param view      */     public void QueryAll(View view) {         List listStudents = DbHelper.queryAllStudent();         if (listStudents == null) {             LogUtils.d("没有数据");             return;         }         for (int i = 0; i < listStudents.size(); i++) {             LogUtils.d("id:" + listStudents.get(i).getId() + "_name:" + listStudents.get(i).getName());         }     }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3