zoukankan      html  css  js  c++  java
  • Android持久化存储——(包含操作SQLite数据库)

    《第一行代码》读书手札


    你可能会遇到的问题:解决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 (
    " +
                "	 id integer primary key autoincrement ,
    " +
                "	 author text,
    " +
                "	 pages integer ,
    " +
                "	 price real,
    "
                "	 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);
    

    查询图

    这里写图片描述

  • 相关阅读:
    做项目时写的数据库操作类。SqlHelper.cs(三)
    写的登录三层结构demo(工厂模式)
    在GridView中进行排序
    微信小程序 POST请求
    mysql replace into用法详细说明
    ThinkPHP Where 条件中使用表达式
    Google发转码工具 可将安卓程序转至iOS
    IOS笔记 本地化多语言支持
    persits.jpeg 水印组件
    PHP 数组操作
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665753.html
Copyright © 2011-2022 走看看