Android官方开发文档Training系列课程中文版:数据存储之数据库存储

原文地址:http://android.xsoftlab.net/training/basics/data-storage/databases.html

对于保存重复的结构化的数据最理想的方式就是存到数据库,比如联系人信息。这节课假定你有SQL数据库基础,会帮助你开始学习Android上的SQLite数据库。你将通过使用android.database.sqlite包下API来操作数据库。

定义架构以及契约

SQL数据库的主要原则之一就是架构:一份数据库组织结构的正式声明。架构反映在SQL语句中,你可以使用它来创建数据库。你可能会发现它对于创建一个辅助类来说是非常有帮助的。我们所已知的contract类,它明确的指明了在系统化和自我记录化的方式下的布局模式。

contract类是一个契约容器,它定义了URI、TABLE、COLUMN的名称。contract类允许你使用相同的契约访问处于同一个包下的所有类。它可以使你在一个地方改了列名,然后让这个更改消息在代码中传播(Tips:这里应该说的是观察者模式)。

组织一个contract类的最好方式就是在类的根级中定义全局的数据库。然后对每一个表都创建一个内部类并且在内部类中列举出它的每一列列名。

Note:内部类可以通过实现BaseColumns接口,继承一个被称为_ID的主键,一些Android中的类比如cursor adapter会期望拥有这个主键,不过这不是必须的,但是它可以有助于数据库在Android框架层中运行的更协调。

下面的小片段定义了一个单表,并列举出了它表名和列名:

public final class FeedReaderContract {// To prevent someone from accidentally instantiating the contract class,// give it an empty constructor.public FeedReaderContract() {}/* Inner class that defines the table contents */public static abstract class FeedEntry implements BaseColumns {public static final String TABLE_NAME = "entry";public static final String COLUMN_NAME_ENTRY_ID = "entryid";public static final String COLUMN_NAME_TITLE = "title";public static final String COLUMN_NAME_SUBTITLE = "subtitle";...}
}

使用SQL Helper创建一个数据库

一旦定义了数据库的模型,你应该实现可以创建并可以为维护数据库以及表的方法。下面是创建表、删除表的一些典型声明:

private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES ="CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +FeedEntry._ID + " INTEGER PRIMARY KEY," +FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +... // Any other options for the CREATE command" )";
private static final String SQL_DELETE_ENTRIES ="DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;

就像保存在内部存储器上的文件,Android会将你的数据库文件保存到与应用程序有关的私有磁盘空间内。所以你的数据是安全的,因为默认情况下这块区域是不可以被其它应用程序访问的。

在SQLiteOpenHelper类中有一系列非常有用的API。当使用这个类的API操作数据库的引用时,系统会潜在的执行耗时操作。所以创建和更新数据库的时间,应该放在需要操作的时候操作,而不是在应用启动的时候操作。你需要操作的所有事情需要通过调用getWritableDatabase()或者getReadableDatabase()来完成。

Note:因为这些操作可能会长时间运行,所以要确保调用getWritableDatabase()或getReadableDatabase()的线程是工作线程,比如使用AsyncTask或者IntentService。

为了使用SQLiteOpenHelper,需要创建SQLiteOpenHelper的一个子类然后重写onCreate(), onUpgrade()和onOpen()回调方法。你可能还需要实现onDowngrade(),但在这里不是必须的。
下面是SQLiteOpenHelper的实现样例,其中使用了上面所示的部分代码:

public class FeedReaderDbHelper extends SQLiteOpenHelper {// If you change the database schema, you must increment the database version.public static final int DATABASE_VERSION = 1;public static final String DATABASE_NAME = "FeedReader.db";public FeedReaderDbHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}public void onCreate(SQLiteDatabase db) {db.execSQL(SQL_CREATE_ENTRIES);}public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// This database is only a cache for online data, so its upgrade policy is// to simply to discard the data and start overdb.execSQL(SQL_DELETE_ENTRIES);onCreate(db);}public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {onUpgrade(db, oldVersion, newVersion);}
}

如果需要访问数据库,需要实例化SQLiteOpenHelper的子类:

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());

放置信息到数据库

通过往insert()方法中传递ContentValues对象可以向数据库中插入数据:

// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);
// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(FeedEntry.TABLE_NAME,FeedEntry.COLUMN_NAME_NULLABLE,values);

insert()方法的第一个参数是一个简单的表名,第二个参数提供了当ContentValues为空的时候framework插入NULL值的那一列的列名(如果你想设置这个参数为”null”,那么当插入的值为空的时候framework将不会空值插入到数据库)。

从数据库中读取信息

为了可以从数据库读取数据,应该使用query()方法,传入你的选择条件以及期望返回的那几列。这个方法结合了insert()方法和update()方法的基础,定义了你想匹配的那几列,但并不插入数据。查询返回的结果会在Cursor对象中。

SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {FeedEntry._ID,FeedEntry.COLUMN_NAME_TITLE,FeedEntry.COLUMN_NAME_UPDATED,...};
// How you want the results sorted in the resulting Cursor
String sortOrder =FeedEntry.COLUMN_NAME_UPDATED + " DESC";
Cursor c = db.query(FeedEntry.TABLE_NAME,  // The table to queryprojection,                               // The columns to returnselection,                                // The columns for the WHERE clauseselectionArgs,                            // The values for the WHERE clausenull,                                     // don't group the rowsnull,                                     // don't filter by row groupssortOrder                                 // The sort order);

为了查看cursor中的每一行,需要使用Cursor的移动方法,在你开始读取数据之前你需要一直调用这个方法。通常情况下,你应该在最开始调用moveToFirst()方法,它会将读取位置放置到第一个结果实体所在的位置。对于每一行来说,你可以通过调用Cursor类中的其中一个方法读取一个列值,比如使用getString(),getLong()。对于每一个get方法,你必须给这些方法传递一个要读取那一列的索引位置值,你可以通过getColumnIndex()或者getColumnIndexOrThrow()获得索引位置值:

cursor.moveToFirst();
long itemId = cursor.getLong(cursor.getColumnIndexOrThrow(FeedEntry._ID)
);

从数据库中删除信息

如果要从数据库表中删除一行,你需要提供可以标识那一行的选择条件。数据库API提供了一种机制,用于创建选择条件,这种机制可以防止被SQL注入。这种机制会将选择规范划分为选择条件和选择参数。选择条件用于定义查找的列,也允许同时查找多列。选择参数的值会测试绑定到条件上的对应值。因为结果不会像常规的SQL语句那样被处理,它会用于免疫SQL注入的。

// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);

更新数据库

如果需要修改数据库值的子集,请使用update()方法。

更新表的方法结合了insert()的内容语法与delete()的where语法。

SQLiteDatabase db = mDbHelper.getReadableDatabase();
// New value for one column
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
// Which row to update, based on the ID
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };
int count = db.update(FeedReaderDbHelper.FeedEntry.TABLE_NAME,values,selection,selectionArgs);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

五笔字根表口诀的通俗易懂讲解

五笔字根表口诀的通俗易懂讲解 从上面五笔学习导图,我们不难看出,五笔只包含两个部分,一是独立字。二是字根字。 1 先来讲解独立字。 独立字就是不用字根就可以输出的汉字,独立字包含一级简码,按键字两种。…

论文浅尝 | 基于知识图谱难度可控的多跳问题生成

论文笔记整理:谭亦鸣,东南大学博士生,研究兴趣:知识图谱问答。来源:ISWC 2019链接:https://link.springer.com/content/pdf/10.1007%2F978-3-030-30793-6_22.pdf本文提出一个end2end神经网络模型以知识图谱…

LeetCode 933. 最近的请求次数(queue)

1. 题目 写一个 RecentCounter 类来计算最近的请求。 它只有一个方法:ping(int t),其中 t 代表以毫秒为单位的某个时间。 返回从 3000 毫秒前到现在的 ping 数。 任何处于 [t - 3000, t] 时间范围之内的 ping 都将会被计算在内,包括当前&…

如何融合深度学习特征向量?

本文转载自公众号“夕小瑶的卖萌屋”,专业带逛互联网算法圈的神操作 -----》我是传送门 关注后,回复以下口令: 回复【789】 :领取深度学习全栈手册(含NLP、CV海量综述、必刷论文解读) 回复【入群】&#xf…

将军令:数据安全平台建设实践

背景 在大数据时代,数据已经成为公司的核心竞争力。此前,我们介绍了美团酒旅起源数据治理平台的建设与实践,主要是通过各种数据分析挖掘手段,为公司发展决策和业务开展提供数据支持。 近期,业内数据安全事件频发&#…

Android官方开发文档Training系列课程中文版:与其它APP交互之将用户带到其它的APP

原文地址:http://android.xsoftlab.net/training/basics/intents/index.html 导言 一个Android APP应用通常会有若干个Activity。每一个Activity所展示的用户界面用于允许用户执行特定的任务(比如浏览地图或者是拍照)。为了把用户从一个activity带到另一个activit…

视频推荐

基于标签的实时短视频推荐系统:https://zhuanlan.zhihu.com/p/80069135 视频爆量攻略——YouTube视频推荐算法详解https://zhuanlan.zhihu.com/p/79172083

开源开放 | 图数据交互可视化分析框架 InteractiveGraph v0.3 版本发布

图数据交互可视化分析框架 InteractiveGraph 日前发布 v0.3 版本,下载地址:https://github.com/grapheco/InteractiveGraph/releases/tag/0.3.1图数据模型具有对实体关系的表达能力强、属性 及结构可扩展性好、关联查询高效等优势。在对海量 的多元异构信…

LeetCode 589. N叉树的前序遍历(前序遍历)

文章目录1. 题目2. 解题2.1 递归2.2 循环1. 题目 2. 解题 2.1 递归 class Solution { public:vector<int> preorder(Node* root) {vector<int> ans;preRec(root,ans);return ans;}void preRec(Node* root, vector<int> &ans) {if(root NULL)return;ans…

打脸!一个线性变换就能媲美“最强句子embedding”?

文 | 苏剑林&#xff08;追一科技&#xff09;编 | 小轶小编&#xff1a;前几周小屋刚推完《还在用[CLS]&#xff1f;从BERT得到最强句子Embedding的打开方式&#xff01;》&#xff0c;苏神就来打脸了_(:з」∠)_BERT-flow来自论文《On the Sentence Embeddings from Pre-trai…

Android官方开发文档Training系列课程中文版:与其它APP交互之从Activity获得结果

原文地址&#xff1a;http://android.xsoftlab.net/training/basics/intents/result.html 启动其它Activity并不是单方向的。你也可以启动其它Activity然后接收返回结果。如果要接收结果&#xff0c;应该调用startActivityForResult()而不是startActivity()。 举个例子&#…

AI Challenger 2018:细粒度用户评论情感分析冠军思路总结

2018年8月-12月&#xff0c;由美团点评、创新工场、搜狗、美图联合主办的“AI Challenger 2018全球AI挑战赛”历经三个多月的激烈角逐&#xff0c;冠军团队从来自全球81个国家、1000多所大学和公司的过万支参赛团队中脱颖而出。其中“后厂村静静”团队-由毕业于北京大学的程惠阁…

基于PaddleRec的用户点击率预测

基于PaddleRec的用户点击率预测 一、前言推荐系统的痛点 二、推荐系统的数据获取获取数据的三种方法1.使用现成的数据集2.网络爬虫3.调查问卷 三、数据处理PaddleRec推荐数据集格式1.slot:value的格式说明2.只有value的输入数据格式 四、完成点击率预测的具体实现1.首先安装P…

论文浅尝 | 融入知识的弱监督预训练语言模型

论文笔记整理&#xff1a;叶群&#xff0c;浙江大学计算机学院&#xff0c;知识图谱、NLP方向。会议&#xff1a;ICLR 2020链接&#xff1a;https://arxiv.org/pdf/1912.09637.pdf Abstract预训练语言模型不仅在传统的语言学任务上取得了很好的表现&#xff0c;在一些涉及到背景…

2021 年 1 月程序员薪资出炉,持续上涨!你过平均线了吗?

瑟瑟发抖&#xff01;程序员薪资报告又来了。2021 年 1 月的薪资报告一定能给你个大惊喜&#xff01;程序员薪资扶摇直上。&#xff08;2021年1月程序员收入情况&#xff09;1 月全国程序员平均工资 14915 元&#xff0c;工资中位数 12500 元&#xff0c;其中 96% 的人工资介于…

LeetCode 590. N叉树的后序遍历(后序遍历)

文章目录1. 题目2. 解题2.1 递归2.2 循环1. 题目 2. 解题 2.1 递归 class Solution { public:vector<int> postorder(Node* root) {vector<int> ans;postRec(root, ans);return ans;}void postRec(Node* root, vector<int> &ans){if (root NULL)return…

人物志 | MIT 科技创新“远见者”:美团 NLP 负责人王仲远

2019 年 1 月 21 日&#xff0c;《麻省理工科技评论》发布了 2018 年“35 岁以下科技创新 35 人”&#xff08;35 Innovators Under 35&#xff09;中国榜单&#xff0c;美团点评AI平台部 NLP 中心负责人、点评搜索智能中心负责人王仲远获评为“远见者”。 Innovators Under 35…

Android官方开发文档Training系列课程中文版:与其它APP交互之允许其它APP启动你的Activity

原文地址&#xff1a;http://android.xsoftlab.net/training/basics/intents/filters.html 在前两节课程中我们只关注了事情的一面&#xff1a;从你的APP启动其它APP。但是如果你的APP可以执行一些功能&#xff0c;并且这些功能可以被其它APP所利用&#xff0c;那么你可以做一…

论文浅尝 | GraphSAINT—基于图采样的归纳学习方法

论文笔记整理&#xff1a;杨海宏&#xff0c;浙江大学博士生&#xff0c;研究方向为开放世界下的多语言知识问答。1. 简介受显存的因素限制&#xff0c;应用图神经网络于大规模图学习任务上面临“邻居爆炸&#xff08;Neighbor Explosion&#xff09;”问题&#xff0c;导致网络…