《第一行代码》读书手札


你可能会遇到的问题:解决File Explorer 中无显示问题


Android中,持久化存储,常见的一共有三种方法实现


(一.)利用文件存储

文件存储是Android存储中,最基本的一种存储方式。

就是利用Context类的方法,获取输入输出字节流对象,之后,就是java的文件操作。

特点:

  1. 不对存储的数据进行任何格式化的处理

  2. 所有的数据,都原封不动的保存在文件中。

  3. 基于以上两点,文件存储只适合存储简单的文本数据

  4. 假如,非要存储一些复杂数据,就需要自己定义一套格式,便于将数据解析出来。

    简单说,就适合存储简单的数据文本,复杂的数据,请使用下面介绍的两种方法存储

a. 如何将数据存储到文件中

使用Context类的openFileOutput()方法,将数据存储到文本中,从名字也可

以看出来Output,将内存中的数据输出到硬盘中的,是用来保存数据的。


openFileOutput()方法


接受两个参数

  1. 第一个参数: 表示保存的文件的名字,这个名字中不能包含路径,因为所有的文件都是默认存

    储到 /data/data/<包名>files/ 目录下。

  2. 第二个参数: 表示文件的操作模式。目前只有两种模式了,其他模式由于安全性已经废弃了。

    MODE_PRIVATE :若文件已存在,则复写文件。

    MODE_APPEND :若文件已存在,则续写;文件不存在,就新建,再写文件。

返回值

1. 返回一个FileOutputStream 对象,就是java中的字节流对象,下面操作跟

java的IO流一样。

注意返回的是字节流,当我们操作的是文本数据,想使用字符流,需要转换流转换一下。

b.利用FileOutputStream对象,将数据存储到文件中

获取到FileOutputStream对象,存储文件,跟Java中一样。笔者,自定义一个save()方法,将数据存储到本地文件中。
    /**
* 保存数据到文本中
*
* @param inputText 需要保存的文本
*/
public void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null; // 异常不能抛出去,因为活动的父类,没有抛出异常,作为子类也不能抛出异常
try {
//文件名中,不能包含路径
out = openFileOutput("myData", Context.MODE_PRIVATE);
// 转换流
writer = new BufferedWriter(new OutputStreamWriter(out));
// 将数据保存到本地
writer.write(inputText);
// 刷新缓冲区
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭缓冲区
try {
if (out != null) {
out.close();
}
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

上述方法需要在活动的onDestory()中调用,在销毁活动的时候,将活动中的数

据,保存下来。

    在onDetory()方法中调用sava方法
    /**
* 重写onDestory()方法
* 在里面保存数据
*/
@Override
protected void onDestroy() {
super.onDestroy();
String txt = edt_in.getText().toString();
//文件为空,就不再保存
if (!txt.equals(""))
save(txt); }

c.从文本中读取数据

Context还提供了一个openFileInput()方法,返回一个FileInputStream对象,

接下来,就是跟java一样的操作。

    /**
* 读取文件中的数据
*/
public String load(){
// Context的openFileInput()方法,返回一个字节流对象
FileInputStream inputStream = null ;
// 字符操作,使用带缓冲区的字符流
BufferedReader reader = null ;
// 字符串缓冲区,为了防止数据过多的情况下,频繁的创建字符串
StringBuffer content = new StringBuffer() ; try {
// 获取字节流对象。参数为 文件名
// 它会自动的去保存的时候的路径
// /data/data/<包名>files/ 目录下寻找
inputStream = openFileInput("myData") ;
// 将字节流转换为带缓冲区的字符流
reader = new BufferedReader(new InputStreamReader(inputStream)) ;
// 做标记,只要line不为null,就一直读取
// 顺便临时保留每次读取的行内容
String line = "" ;
// 每次读取一行内容
while((line = reader.readLine())!=null){
// 将读取的内容,保存到字符串缓冲区中
content.append(line) ;
} }catch (IOException e){
e.printStackTrace();
}
return content.toString() ;
}

d.恢复数据

b中,在活动被销毁的时候,将瞬时数据保存到本地文件中,那么,再次打开活动的时候,怎么将数据恢

复到活动中呢?

恢复数据,很简单,活动在第一次被创建的时候,一定会调用onCreate()方

法,我们就在这里,做恢复数据的工作。恢复之前,先做个判断,判读读取的数

据,是否为空串啥的。

 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获得控件对象
edt_in = (EditText) findViewById(R.id.edt_in);
// 读取数据
String input = load() ;
// 判断是否需要恢复数据
// TextUtils.isEmpty(input)
// 会判断是否为空串或者为null
if(!TextUtils.isEmpty(input)){
// 非空就恢复数据
edt_in.setText(input);
// 人性化操作,将输入的光标移动到文本末尾
edt_in.setSelection(input.length());
}

(二.)利用 SharePreferences 存储

特点:

1. 使用键值对存取数据

2. 保留数据原有格式,存进去的是整形,取出来的还是整形,

    与利用文件存储不一样,利用文件存储,会将所有数据,都当做字符串保存

3. 数据的存储,都是存储到文件中,这里是存储到SharePreferences文件中,该

文件是xml格式。


想要将数据存储到SharePreferences文件中,首先需要获取

SharePreferences对象,其中,SharePreferences文件被保存在/data/data/

<包名>/shared_prefs/目录下


a.如何获取SharePreferences对象


1.Context类的getSharePreferences()方法

该方法接收两个参数

第一个参数,是SharePreferences文件的名字,如果文件不存在,就会自动新建一个。SharePrefe

rences文件被保存在/data/data/<包名>/shared_prefs/目录下

第二个参数,代表操作模式,目前只剩下一个默认模式:MODE_PRIVATE,和直接传入0效果一样,表示

只有当前的应用程序,才可以对该SharePreferences文件进行读写。

2.Activity类的getPreferences()方法

总体上跟Context的getSharePreferences()方法很类似

该方法只接收一个参数

参数,代表操作模式,目前只剩下一个默认模式:MODE_PRIVATE,和直接传入0效果一样,表示只有

当前的应用程序,才可以对该SharePreferences文件进行读写。

该房啊会自动将当前活动的类名作为SharePreferences的文件名。

3.PreferenceManger类getDefaultSharedPreferences() 方法

该方法是一个静态方法

接收一个Context参数,可以将当前活动的对象传进去,活动是一个Context类型

会自动将当前应用程序的包名作为前缀,来命名SharePreferences文件

b.如何存储数据


  1. 调用SharePreferences类的edit()方法,获得SharePreferences.Editor对象

  2. 将数据添加到SharePreferences.Editor对象中;

    添加什么类型的数据就使用对应的方法:
    
    添加字符串,putString()
    
    添加整形,putInt()
  3. SharePreferences.Editor对象的apply()方法,提交数据。


获取 SharePreferences对象,并保存储数据:

 /**
* 将数据存储到SharePreferences文件中
*/ public void save() {
// 获取SharePreferences对象
SharedPreferences preferences = getSharedPreferences("mySharePres", 0);
// 获取SharePreferences.Editor对象
SharedPreferences.Editor editor = preferences.edit();
// 获取数据
String str = edt_str.getText().toString();
String str_num = edt_int.getText().toString();
// 只要有一个为空,就不保存
if (TextUtils.isEmpty(str) || TextUtils.isEmpty(str_num)) {
return;
}
// 进行转换
int num = Integer.parseInt(str_num);
// 保存数据,键值对
editor.putInt("num",num) ;
editor.putString("str",str) ;
// 提交数据
editor.apply(); }

c.如何恢复数据


  1. 获得SharePreferences

  2. 调用getXXX()方法,获取对应的数据

    该方法接收两个参数
    
    第一个参是键值对的键;
    
    第二个参数是默认值,就是没找到传入的键,就返回这个默认值

    /**
* loading 方法
*/
public void load(){
// 获取SharePres 对象
SharedPreferences preferences = getSharedPreferences("mySharePres",0) ;
// 获取数据
String str = preferences.getString("str","haha") ;
int num = preferences.getInt("num",0) ;
// 设置数据
edt_str.setText(str);
edt_int.setText(num+"");
}

可以使用SharedPreferences,做一个记住密码的功能

笔者做了一个demo,主要功能就是,用户输入用户名和密码以后,在点击登录按钮的时候,

先做个判断,判断是否选中记住密码,如果选中,则保存用户名和密码。

实质,无论是否选中记住密码,都会执行记住密码这一动作,唯一的差别,就是保存的密码,是密码还

是空串的区别。选中保存密码,就保存密码;没选中保存尼玛,就将密码保存为空串。

记住密码功能的完整代码:

/**
* 记住密码类
*/
public class Keep_name_paw extends AppCompatActivity implements View.OnClickListener {
// 设置为全局变量,因为下面的多个方法中都会用到
// 获取SharePres对象
// 权限设置为append,
SharedPreferences preferences ;
// 获取Editor对象
SharedPreferences.Editor editor ; EditText edt_name, edt_pass;
CheckBox checkBox;
Button btn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_keep_name_paw); preferences = getSharedPreferences("keepNamepass", MODE_APPEND);
editor = preferences.edit(); edt_name = (EditText) findViewById(R.id.edt_name);
edt_pass = (EditText) findViewById(R.id.edt_pass);
btn = (Button) findViewById(R.id.button);
checkBox = (CheckBox) findViewById(R.id.checkBox);
btn.setOnClickListener(this); /*
对名字输入进行监听,如果这个用户名,之前选过记住密码,
就自动为其补全密码
使用addTextChangedListener()监听器
需要复写三个方法,我们这里只用到文字发现改变的逻辑,
因此,另外两个方法,为空就好了
*/
edt_name.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 去SharePres文件中查找
String key = edt_name.getText().toString() ;
String value = load(key) ;
// 设置密码框
edt_pass.setText(value);
} @Override
public void afterTextChanged(Editable s) {}
}) ;
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
// 读取数据
String key = edt_name.getText().toString();
String value = edt_pass.getText().toString();
// 判断是否选中记住密码
if (!checkBox.isChecked()) {
// 如果没选中
// 就将之前保存的数据,的值,用空白替代
// 这里我们,不能调用editor.clear()方法,
// 这样整个SharePres文件就会被删除,其他用户的数据也被删除了 // 就是用空白代替值value,进行保存
value = "";
}
// 进行保存
save(key, value);
break;
}
} /**
* 使用SharePreferences保存数据
*
* @param key 键
* @param value 值
*/
void save(String key, String value) {
// 保存数据
// key就直接使用用户名,这样可以记住不同的账号和对应的密码
editor.putString(key, value);
// 提交数据
editor.apply(); } /**
* 加载数据
*/
String load(String key) {
String value = null;
// 读取数据,
// 第二个参数是默认值,如果没有对应的键,就返回默认值,这里是空串
value = preferences.getString(key, "");
return value;
}
}

布局图片

<!--布局代码-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_keep_name_paw"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <LinearLayout
android:layout_margin="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <TextView
android:text="账 号"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2" /> <EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:id="@+id/edt_name"
android:layout_weight="1" />
</LinearLayout> <LinearLayout
android:layout_margin="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <TextView
android:text="密 码"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView3" /> <EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:id="@+id/edt_pass"
android:layout_weight="1" />
</LinearLayout> <CheckBox
android:text="记住密码"
android:textColor="#abd123"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/checkBox" /> <Button
android:text="登 录"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:layout_gravity="right"
android:layout_margin="10dp"
android:id="@+id/button" />
</LinearLayout>

(三)利用SQL数据库存储

在前面介绍的两种方法中,存储的数据都是一些简单的数据;假如,我们需要保存一些具有关系型的数

据,前面的2种方法,将不再好用;对于关系型数据,首选项应该是数据库存储。

巧了,Android系统是内嵌sql数据库的。

这里将介绍两种操作数据库的方式。

1、使用SQLiteOpenHelper帮助类

Android为了我们,可以方便的操控数据库,提供了这个帮助类。感谢Android给与我们方便

a、什么是 SQLiteOpenHelper 帮助类

特点

1. 是一个抽象类,因此,我们需要自己创建一个帮助类去继承它;


2. 有两个抽象方法

创建数据库 onCreate( );

升级数据库 onUpgrade( ) ;


3. 有两个实例方法

返回SQLiteDatabase对象。

getReadableDatabase( ) ;

getWriteableDatabase( ) ;


共同点

这两个方法可以创建或者打开一个现有的数据库就是说,如果数据库已经存

在,就直接打开;不存在,就先新建一个数据库,再打开,并返回一个可对数

据库进行读写操作的对象。千万不要被字面意思骗了,以为Readable,就只能

进行读,不能对数据库进行写操作,两个方法,返回的对象,对数据库既可以进

行写操作,也可以进行读操作。


不同点

在数据库可以写入的情况下

两个方法返回的对象,都可以对数据库进行读写操作。

在数据库不可写入的时候

getReadableDatabase( ) 方法,将以只读方式打开数据库;

getWriteableDatabase( )方法将抛出异常;


b、如何创建自己的帮助类

道理我都懂,怎么创建自己的数据库帮助类?

上面已经提到,需要我们重写一个帮组类,继承自SQLiteOpenHelper类。

要想继承一个类,首先需要明确人家的构造器是什么样的?

SQLiteOpenHelper类一共有两个构造器,这里我们选择参数个数少的那一个,一个有四个参数。

第一个参数 Context

当前调用SQLiteOpenHelper的Activity对象的context

第二个参数 String

数据库的名字;创建数据库的名字,就是依据它;要加上后缀.db

第三个参数 SQLiteDatabase.CursorFactory

在查询数据的时候,可以返回一个自定义的Cursor,这里写null即可

第四个参数 int

表示当前数据库的版本号,用于对数据库的升级

c、利用自己的数据库帮助类,创建数据库

创建的数据库文件,保存在/data/data/<包名>/databases/目录下

步骤

1. 根据b中的构造器,创建自己数据库帮助类的实例

2. 再调用继承来的实例方法 getReadableDatabase( )、 getWriteableDatabase( )

3. 在调用继承来的实例方法,创建数据库时,我们复写的SQLiteOpenHelper类

的onCreate( ) 方法会被调用。通常在这里执行创建表的操作。


建立Book表的SQL语句:

很简单的sql语句

假如,你不太会sql语句,没关系,后面的LitePal操控数据库,将不需要写sql语句,完全是面向对象

的思想,在操控数据库。
create table Book (
id integer primary key autoincrement ,
author text,
pages integer ,
price real )

自定义的数据库帮助类

注意onCreate()方法
public class MySqliteOpenHelper extends SQLiteOpenHelper{

    String book_sql = "create table Book (\n" +
"\t id integer primary key autoincrement ,\n" +
"\t author text,\n" +
"\t pages integer ,\n" +
"\t price real,\n"
"\t name text )" ; Context context ;
public MySqliteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context ;
} /**
* 在调用实例方法的时候,如果数据库还未创建,这个方法就会被回调
* 这个方法,仅在创建数据库的时候,得到调用
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(book_sql);
//这个Toast仅会弹出一次
Toast.makeText(context,"数据库已创建",Toast.LENGTH_SHORT).show();
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

通过点击按钮创建数据库

在活动类中,对按钮设置监听器,在监听器里面创建数据库
public class Create_sql extends AppCompatActivity{

    private Button btn_createSql ;
private MySqliteOpenHelper mySqliteOpenHelper ; @Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_sql_layout);
// 创建自己的数据库帮助类
mySqliteOpenHelper = new MySqliteOpenHelper(this,"myDatabase.db",null,1) ;
// 获取按钮控件
btn_createSql = (Button) findViewById(R.id.btn_createSql);
// 设置监听器
btn_createSql.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 获取可对数据库进行读写的对象
// 当我们第一次点击按钮的时候,会自动创建数据库
mySqliteOpenHelper.getWritableDatabase() ;
}
});
}
}

思考

这里有个问题,既然,我们把创建表的语句,写在onCreate()方法中,但是这个方法仅仅在创建数据

库的时候,会被调用一次。那么我们在以后,还想创建新的表怎么办呢?

答案:

刚刚有一个方法onUpgrade(),我们一直没用,从名字也可以看出,这个方法是升级数据库的。

既然,后续我们需要新增表,说明我们的数据库,需要升级,那么我们,就在这个升级数据库的方法

里,写上我们的逻辑。onUpgrade()方法,当程序发现,数据库版本号不一样的时候,就会调用

这个方法。因此,当我们需要升级数据库的时候,在创建数据库帮助类实例的时候,传入的版本号,

比之前大,就好了。


升级数据库(并不会将原有的数据库删除)

在库里面新增一张表,如果是对原有的表进行更新,需要先将原有的表删除,再新建。否则,程序会报错

因为,并不会将原有的数据库删除,因此,onCreate()方法,不会得到回调。

只会显式的回调onUpgrade()方法,但是我们可以在onUpgrade()方法中显式的调用这个方法。

sql语句

create table Category (
id integer primary key autoincrement,
category_name text,
category_code integer )

onUpgrade()方法

简单的写上新建表语句
  @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(Category_sql);
}

改变数据库的版本号

//        创建自己的数据库帮助类,将版本号从1变为2 。
mySqliteOpenHelper = new MySqliteOpenHelper(this,"myDatabase.db",null,2) ;

总结:

我们可以看出来,我们只需要管理,创建数据库 onCreate( );升级数据库

onUpgrade( ) ;这两个方法。而对于getReadableDatabase( )

getWriteableDatabase( ) ;这两个方法,我们只需要用数据库帮助类实例去调

用即可。当我们调用的时候,如果没有数据库,它们就会回调onCreate()方

法,创建数据库;如果发现数据库版本号发现变化,就会回调onUpgrade( )方

法;否则,就简单的返回一个可对数据库进行读写的对象- - -SQLiteDatabase。

onUpgrade( )中的逻辑:

如果不是只新建一张表,而是需要要在原有表新添加一列呢?

这里需要注意,是否需要保存原有数据,如果不需要保存,直接删除,再新建

表;如果,需要保存原有数据,则将原来的表名,更名为一张临时表,再新建一

张表,这张表中有我们需要的新列,表名字跟原来的表一样。再将临时表中的数

据复制过来,最后,删除临时表。


在Android里,我们并不需要对sql语句如何熟悉!但是,我们却同样可以完成CRUD动作。这都要

归功于数据库帮助类实例方法返回的SQLiteDatabase对象


CRUD- — -添加数据


方法: SQLiteDatabase对象的 insert( )

 接受三个参数;

第一个参数是 表名

想往哪张表里面添加数据,就写哪张表的名字

第二个参数是 默认值,这里我们写null,即可

用于,我们没指定添加数据的情况下,给那些可为空的列,自动赋值为null

第三个参数是 ContentValues对象

该对象,提供了一系列put( )方法重载,利用put方法将数据保存到ContentValues对象中,

put( )方法接受两个参数

第一个参数是表中的列名;

第二个参数是列名对应的数据;

一个ContentValues对象,只能保存一条数据,在有多条数据的时候,每次装完一条数据的时候,需要

clear()一下。

添加数据的代码 :

这里仅给出关键代码,就是在按钮监听器中执行这一段添加数据的逻辑代码。
btn_insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 添加数据,首先需要获取SQLiteDatabase对象
SQLiteDatabase sqLiteDatabase = mySqliteOpenHelper.getReadableDatabase() ;
// 再创建ContentValues对象,保存数据
ContentValues contentValues = new ContentValues() ;
// 添加数据
// 描述第一条数据
contentValues.put("name","第一行代码");
contentValues.put("price","59");
contentValues.put("pages","570");
contentValues.put("author","郭霖");
// 添加第一条数据
sqLiteDatabase.insert("Book",null,contentValues) ;
// 清除第一条数据,再添加第二条数据
contentValues.clear(); // 描述第二条数据
contentValues.put("name","肥嘟嘟左卫门");
contentValues.put("price","46");
contentValues.put("author","野原新之助");
contentValues.put("pages","2");
// 添加第二条数据
sqLiteDatabase.insert("Book",null,contentValues) ; }
});

查看数据库:

笔者刚刚一共点击了3次按钮,因此,生成6条数据;


CRUD- — -更新数据


方法: SQLiteDatabase对象的 update( )

 接受四个参数;

第一个参数是 表名

想往哪张表里面更新数据,就写哪张表的名字

第二个参数是 ContentValues对象

经过上面学习,我们已经知道,这个对象,就像是一个容器,保存,我们的数据;因此,这里,我们将

要更新的数据也放在这里面

第三、四个参数

用于约束更细某一行或者某几行中的数据,如不指定,默认更新所有行。

第三个参数是字符串,相当于where部分,这里写上你想跟新的字段,一般写上?占位符

第四个参数,是一个字符串数组,指明前面的?是谁。

更新数据代码:

//                更新数据,还是需要获取SQLiteDatabase对象
SQLiteDatabase sqLiteDatabase = mySqliteOpenHelper.getReadableDatabase() ;
// 再创建ContentValues对象,保存数据
ContentValues contentValues = new ContentValues() ;
// 写上要更新的数据
contentValues.put("price",50);
// 将name是第一行代码 的数据的price更新为50
sqLiteDatabase.update("Book",contentValues,"name = ? ",new String[]{"第一行代码"}) ;
// 清除之前contentValues的数据,否则下次更新,会将之前的数据也更新进来
contentValues.clear();
contentValues.put("pages",10);
// 将所有pages是130的,都更新为10
sqLiteDatabase.update("Book",contentValues,"pages = ? ",new String[]{"130"}) ;

更新以后数据截图

笔者刚刚又点了2次添加数据按钮,因此数据多了4条

并且笔者,特意contentValues.clear();把这行注释了,

因此,我们可以发现之前pages=130的,不但pages被更新为10,就连price也被更新为50了

因此,验证了,笔者之前说的话:如果,没有清除之前contentValues的数据,下次更新,会将之前的

数据也更新进来


## CRUD- — -删除数据

----------

方法: SQLiteDatabase对象的 update( )

 接受四个参数;

第一个参数是 表名

想删除哪张表的数据,就写哪张表的名字

第二、三个参数

同样是用来删除哪一行的数据,不指定的话,就删除所有行。

删除第一行代码的数据

肥嘟嘟左卫门,是小新的书诶!不能删除。。委屈一下郭神
                SQLiteDatabase sqLiteDatabase = mySqliteOpenHelper.getReadableDatabase() ;
// 删除第一行代码数据的数据
sqLiteDatabase.delete("Book","name=?",new String[]{"第一行代码"}) ;

效果图:

可以看到,仅剩下小新的书了。


## CRUD- — -查询数据

最重要的一种操作。

方法: SQLiteDatabase对象的 query( )

这个方法的重载非常复杂,最短的一个方法重载,也需要7个参数。

我们,重点看7个参数的重载方法。

但是,并不是每次查询都需要,写满7个参数。大多数情况下,只需要传入少数几个参数,就可以完成查

询操作。

参数

1. table - - - - 指定查询的表名;

2. columns - - - - 指定查询的列名;

3. selection - - - - 指定where的约束条件

4. selectionArgs - - - - 为where中的占位符提供具体的值

5.groupBy - - - - 指定需要group by 的列

6. having - - - - 对group by 的结果进行进一步的约束

7.orderBy - - - - 指定查询结果的排序方式


返回值

方法返回一个Cursor对象,查询到的所有数据都将从这个对象中取出。


获取 Cursor对象中的数据

1. moveToFirst() 先判断 Cursor对象中是否有数据,将数据的指针移到第一

行,有数据,就返回真,没数据就返回假;

2.moveToNext() 将数据指针移动到下一行,同样返回真(有数据)、假

(没有数据);跟迭代器用法类似。

3.获取一行中某个字段的值: 使用Cursor对象的getColumnIndex(列名);获取该列

在表中的索引,再调用Cursor对象的getXXX(索引)方法,即可获取到该列的数

据。

4.最后需要关闭Curson对象

代码:

//                查询数据
SQLiteDatabase sqLiteDatabase = mySqliteOpenHelper.getReadableDatabase() ;
// 写入的参数,代表将整张表数据都查询出来
Cursor cursor = sqLiteDatabase.query("Book",null,null,null,null,null,null);
// 将数据指针移动第一行
if(cursor.moveToFirst()){
do{
int id = cursor.getInt(cursor.getColumnIndex("id")) ;
int pages = cursor.getInt(cursor.getColumnIndex("pages")) ;
String name = cursor.getString(cursor.getColumnIndex("name")) ;
String author = cursor.getString(cursor.getColumnIndex("author")) ;
float price = cursor.getFloat(cursor.getColumnIndex("price")) ; Log.d("sql_query", id+" "+pages+" "+name+" "+author+" "+price);
}while(cursor.moveToNext()) ;
} // 还需要关闭Cursor
cursor.close();

查询图:


查询Book表中,id和name列的数据,其中id必须大于3

  Cursor cursor = sqLiteDatabase.query("Book",new String[]{"id","name"},"id>?",new String[]{"3"},null,null,null);

查询图

Android持久化存储——(包含操作SQLite数据库)的更多相关文章

  1. Android学习之基础知识九 — 数据存储(持久化技术)之SQLite数据库存储

    前面一讲介绍了数据持久化技术的前两种:文件存储.SharedPreferences存储.下面介绍第三种技术:SQLite数据库存储 一.SQLite数据库存储 SQLite数据库是一款轻量级的关系型数 ...

  2. 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)

    1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...

  3. Android数据的四种存储方式之SQLite数据库

    Test.java: /** * 本例解决的问题: * 核心问题:通过SQLiteOpenHelper类创建数据库对象 * 通过数据库对象对数据库的数据的操作 * 1.sql语句方式操作SQLite数 ...

  4. Android中操作SQLite数据库

    我又回到了安卓的学习当中,忙来忙去终于忙的差不多有时间做自己的事情了,这感觉实在是太棒了!!本来想写android的控件以及他们的监视器的,但是我查了查android的手册,基本上都能查到,但是查有些 ...

  5. 在 Android 应用程序中使用 SQLite 数据库以及怎么用

    part one : android SQLite 简单介绍 SQLite 介绍 SQLite 一个非常流行的嵌入式数据库.它支持 SQL 语言,而且仅仅利用非常少的内存就有非常好的性能.此外它还是开 ...

  6. Electron中使用sql.js操作SQLite数据库

    推荐sql.js——一款纯js的sqlite工具. 一.关于sql.js sql.js(https://github.com/kripken/sql.js)通过使用Emscripten编译SQLite ...

  7. Qt 操作SQLite数据库

    项目中通常需要采用各种数据库(如 Qracle.SQL Server.MySQL等)来实现对数据的存储.查询等功能.下面讲解如何在 Qt 中操作 SQlite 数据库. 一.SQLite 介绍 Sql ...

  8. Java操作Sqlite数据库-jdbc连接

    Java操作Sqlite数据库步骤: 1. 导入Sqlite jdbc 本文使用sqlite-jdbc-3.7.2.jar,下载地址 http://pan.baidu.com/s/1kVHAGdD 2 ...

  9. UWP: 在 UWP 中使用 Entity Framework Core 操作 SQLite 数据库

    在应用中使用 SQLite 数据库来存储数据是相当常见的.在 UWP 平台中要使用 SQLite,一般会使用 SQLite for Universal Windows Platform 和 SQLit ...

随机推荐

  1. SpringMVC返回一个JSON对象到界面

    首先明确,在JavaScript中并没有类型这一说,只有一个类型就是var.我们要做的就是让JavaScript得到我们返回的一个对象让它以某种方式去处理数据. 前端代码 后台代码 @RequestB ...

  2. 6、vueJs基础知识06

    vue动画 transition 之前1.0版本是以 属性的形式展示的 <p transition="fade"></p> .fade-transition ...

  3. 大数据技术之kettle(2)——练习三个基本操作

    一.同一数据库两表数据关联更新 实现效果:把stu1的数据按id同步到stu2,stu2有相同id则更新数据 步骤: 1.在mysql中创建两张表: mysql>create database ...

  4. 使用清华源 tensorflow 安装

    1. 超级权限打开cmd.exe 2. pip install --upgrade setuptools 3.  pip install -U --ignore-installed wrapt enu ...

  5. Spark(四十六):Spark 内存管理之—OFF_HEAP

    存储级别简介 Spark中RDD提供了多种存储级别,除去使用内存,磁盘等,还有一种是OFF_HEAP,称之为 使用JVM堆外内存 https://github.com/apache/spark/blo ...

  6. JVM 类加载器的双亲委托机制

    1.类加载器的层次结构 在双亲委托机制中,各个加载器按照父子关系形成了树形结构(逻辑意义),除了根加载器之外,其余的类加载器都有且只有一个父加载器. public class MyTest13 { p ...

  7. Learning Conditioned Graph Structures for Interpretable Visual Question Answering

    Learning Conditioned Graph Structures for Interpretable Visual Question Answering 2019-05-29 00:29:4 ...

  8. TP5 分页数据加锚点

      TP5 分页数据加锚点跳转到相应位置   有这样一个需求,就是加载评论后,点下一页的时候回到相应的位置.  $comment = Db('comment')->order('addtime' ...

  9. idea 启动web项目

    1>Run>Edit Configurations... 2>Server>Open browser>URL>http://localhost:8888/demo2 ...

  10. https://pingcap.com/blog-cn/flame-graph/

    https://pingcap.com/blog-cn/flame-graph/ 因为 TiKV 是自己内部使用了 jemalloc,并没有用系统的 malloc,所以我们不能直接用 perf 来探查 ...