第一行代码学习笔:Android基础----数据持久化

Android中主要提供了三种简单的数据持久化技术:文件、SharePreference、数据库存储。

文件存储

文件存储是Android中最基本的一种数据存储方式。不对存储的内容进行任何的格式化处理,所有数据都是原封不动的保存到文件当中的。比较适合存储一些简单的文本数据或二进制数据。

将数据存储到文件中

Context 类提供了一个openFileOutput()方法,可以用于将数据存储到指定的文件中。

在xml文件中设置一个EditText

<android.support.v7.widget.AppCompatEditText
        android:id="@+id/edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

public class MainActivity extends AppCompatActivity {
    private AppCompatEditText editText = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = findViewById(R.id.edit);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = editText.getText().toString();
        save(inputText);
    }

    public void save(String inputStream){
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            // data 文件名,在文件创建的时候使用的就是这个名称,不可以包含路径,因为所有的文件都是默认存储在/data/data/<pakagename>/file/目录下
            // MODE_PRIVATE 文件的操作模式 MODE_PRIVATE默认操作模式,党指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容
            //MODE.APPEND  如果该文件已存在,就往文件里追加内容,不存在就创建新文件
            //MODE_WORLD_READABLE   MODE_WORLD_WRITEABLE 表示允许其他应用程序对我们程序文件进行读写,容易引起安全漏洞,已被废弃
            out = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (writer!=null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行程序,输入数据,按back键

如何查看数据确实已经被保存了呢?


在data文件夹下



右键保存

用TXT方式打开data文件


从文件中读取数据

和存储数据类似,Context提供了一个openFileInout()方法,用于从文件中读取数据,系统会自动到/data/data/<pakagename>/file/目录下加载这个文件,并返回一个FileInputStream对象,得到这个对象之后,以Java流的方式读取出来。

public class MainActivity extends AppCompatActivity {
    private AppCompatEditText editText = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = findViewById(R.id.edit);
        String inputText = load();
        //可以一次性进行两种空值的判断
        if (!TextUtils.isEmpty(inputText)){
            editText.setText(inputText);
            //将输入光标移动到文本的末尾以便继续书输入
            editText.setSelection(inputText.length());
            Toast.makeText(this,"succeed",Toast.LENGTH_LONG).show();
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = editText.getText().toString();
        save(inputText);
    }

    //将数据从文件中读取出来
    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();
    }
    //将数据写入到文件中
    public void save(String inputStream){
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            // data 文件名,在文件创建的时候使用的就是这个名称,不可以包含路径,因为所有的文件都是默认存储在/data/data/<pakagename>/file/目录下
            // MODE_PRIVATE 文件的操作模式 MODE_PRIVATE默认操作模式,党指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容
            //MODE.APPEND  如果该文件已存在,就往文件里追加内容,不存在就创建新文件
            //MODE_WORLD_READABLE   MODE_WORLD_WRITEABLE 表示允许其他应用程序对我们程序文件进行读写,容易引起安全漏洞,已被废弃
            out = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (writer!=null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

重新运行程序,不输入任何东西


这样就把保存在文件中的数据读取出来了。

SharedPreferences存储

SharedPreferences是使用键值对的方式来存储数据的。在读取数据的时候可以通过这个键把响应的数据读取出来,支持多种数据类型,整型,字符串,Boolean值等。

将数据存储到SharedPreferences中

要想使用SharedPreferences来存储数据,首先需要获取到SharedPreferences对象。Android中主要提供了三种方法得到SharedPreferences对象。

1、Context中的getSharedPreferences()方法

此方法接收两个参数,第一个用于指定SharedPreferences文件名称,如果指定的文件不存在则会创建一个,SharedPreferences文件都是存放在/data/data/<pack name>/shared_prefs/目录下的。第二个参数指定操作模式,目前只有MODE_PRIVATE这一种模式可选,默认操作,和传入0是相同的,表示只有当前的应用程序才可以对这个SharedPreferences进行读写。

2、Activity类中的getPreferences()方法

只接收一个操作模式参数,它会自动将当前活动类名作为SharedPreferences的文件名。

3、PreferenceManager类的getDefaultSharedPreferences()方法。

静态方法,接收一个context参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件,得到SharedPreferences对象之后,就可以开始向SharedPreferences文件中存储数据了,分三步实现。

1)调用SharedPreferences的edit()方法来获取一个SharedPreferences.Editor对象。
2)SharedPreferences.Editor对象添加数据。
3)调用apply()方法将添加的数据提交,完成数据存储操作。

在xml文件中添加Button,在Button的点击事件中保存数据。

 <android.support.v7.widget.AppCompatButton
        android:id="@+id/save_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="save data"/>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton saveData = findViewById(R.id.save_data);
        saveData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //SharedPreferences的文件名为data
                SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
                editor.putString("name","sa");
                editor.putInt("age",18);
                editor.putBoolean("married",false);
                //提交
                editor.apply();
            }
        });
    }
}

查看保存的数据


双击查看


SharedPreferences读取数据

xmlwen文件中增加按钮

<android.support.v7.widget.AppCompatButton
        android:id="@+id/restore_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="restore data"/>

在MainActivity中添加代码

AppCompatButton restoreData = findViewById(R.id.restore_data);
        restoreData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
                //"" 第二个参数是默认值,表示当传入的键找不到对应的值时会以什么样的默认值进行返回
                String name = pref.getString("name","");
                int age  = pref.getInt("age",0);
                boolean married = pref.getBoolean("married",false);
                Log.d("MainActivity"," name is "+name);
                Log.d("MainActivity"," age is "+age);
                Log.d("MainActivity"," married is "+married);
            }
        });

重新运行程序


SQLite数据库存储

Android为了让我们更方便的管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单的对数据库进行创建和升级。

创建数据库

SQLiteOpenHelper是一个抽象类,需要自己创建一个帮助类去继承它,有两个非常重要的实例方法,getWritableDatabase()和getReadableDatabase()。这两个方法都可以创建或打开一个现有的数据库(数据库已存在,打开,不存在创建),并返回一个可对数据库进行读写操作的对象。不同的是当数据库不可写入时(如磁盘已满),getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()方法则出现异常。创建的数据库文件 存放在/data/data/<pack name>/databases/目录下。

创见MyDatabaseHelper

public class MyDatabaseHelper extends SQLiteOpenHelper {
    private Context mContext;
    public static  final  String CREARE_BOOK = "create table Book ("//表名 Book
            + "id integer primary key autoincrement,"// primary 主键  autoincrement ID自动增长
            +"auther text,"//text 文本
            +"price real,"// real 浮点型
            +"pages integer,"
            +"name text )";

    /**
     *
     * @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);
        this.mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREARE_BOOK);
        Toast.makeText(mContext,"Create succeed",Toast.LENGTH_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int olderVersion, int newVersion) {

    }
}

在xml文件添加按钮

<android.support.v7.widget.AppCompatButton
       android:id="@+id/create_database"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="create database"/>


public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
        AppCompatButton createDatabase = findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //
                dbHelper.getWritableDatabase();
            }
        });
    }
}

运行程序


使用SQLiteStudio打开数据库


数据库创建完毕。

升级数据库

MyDatabaseHelper中创建Category表,并在onUpgrade()中实现数据库的更新。

public class MyDatabaseHelper extends SQLiteOpenHelper {
    private Context mContext;
    public static  final  String CREARE_BOOK = "create table Book ("//表名 Book
            + "id integer primary key autoincrement,"// primary 主键  autoincrement ID自动增长
            +"auther text,"//text 文本
            +"price real,"// real 浮点型
            +"pages integer,"
            +"name text )";

    public static  final  String CREARE_CATEGORY = "create table Category ("//表名 Category
            + "id integer primary key autoincrement,"// primary 主键  autoincrement ID自动增长
            +"category_name text,"//text 文本
            +"category_code integer)";

    /**
     *
     * @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);
        this.mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREARE_BOOK);
        db.execSQL(CREARE_CATEGORY);
        Toast.makeText(mContext,"Create succeed",Toast.LENGTH_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int olderVersion, int newVersion) {
        //如果存在Book表或 Category表 先删除掉
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }
}


在MainActivity中修改代码

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        AppCompatButton createDatabase = findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //
                dbHelper.getWritableDatabase();
            }
        });
    }
}

先前版本号为1,现在设置为2,实现数据库的升级。


数据库中已经新添加了Category表,数据库升级成功。

添加数据

SQLiteOpenHelper的getWritableDatabase()和getReadableDatabase(),不仅可以用于创建和升级数据库,这两个方法还都会返回一个SQLiteDatabase对象,借助这个对象就可以对数据库进行CRUD(添加,查询,更新,删除)操作了。

MainActicity中

//添加数据
        AppCompatButton addData = findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                //添加第一条数据
                values.put("name","The Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages",456);
                values.put("price",16.96);
                //插入第一条数据
                //Book 表名
                // null 用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL ,一般不用,传入null就行
                //values ContentValues对象,提供一系列的put方法重载,用于向ContentValues中添加数据
                db.insert("Book",null,values);
                values.clear();
                //添加第二条数据
                values.put("name","The Lost Symbol");
                values.put("author","Dan Brown");
                values.put("pages",510);
                values.put("price",19.95);
                //插入第二条数据
                db.insert("Book",null,values);
            }
        });

运行程序


数据添加成功

更新数据

MainActicity中

//更新数据
        AppCompatButton updateData = findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price",10.99);
                //第三个参数  对应SQL语句的where部分,表示更新所有name等于?的行,而?是一个占位符,
                // 可以通过第四个参数提供一个字符串数组为第三个参数中的每个占位符指定相应的内容
                //将名字是The Vinci Code的这本书价格改为10.99
                db.update("Book",values,"name=?",new String[]{"The Vinci Code"});
            }
        });

运行程序


价格已从16.96变为10.99,数据更新成功。

删除数据

 
//删除数据
        AppCompatButton deleteData = findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //第二三个参数用于约束删除某一行 或是某几行的数据,不指定的话就是删除所有行。
                //删除pages超过500 的书
                SQLiteDatabase db = dbHelper.getWritableDatabase();db.delete("Book","pages >?",new String[]{"500"});
            }
        });

运行程序
 
书已经变为了一本,删除数据成功

查询数据

 //查询数据
        AppCompatButton queryBitton = findViewById(R.id.query_data);
        queryBitton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 第一个参数   表名
                // 第二个参数  指定去哪查询,不指定查询所有
                //第三四个参数 约束查询某一行或某几行数据,不指定查询所有行
                //第五个参数  指定需要去group by的列,不指定表示不对查询结果进行group by
                //第六个参数  用于对group by之后的数据进行过滤,不指定表示不进行过滤
                //第七个参数  指定查询结果的排序方式,不指定表示默认排序
                Cursor cursor = db.query("Book",null,null,null,null,null,null);
                //将数据的指针移动到第一行的位置
                if (cursor.moveToFirst()){
                    do {
                        //getColumnIndex() 取到某一列在表中对应的位置索引,
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        Log.d("MainActivity","book name is  "+name);
                        Log.d("MainActivity","book author is  "+author);
                        Log.d("MainActivity","book pages is  "+pages);
                        Log.d("MainActivity","book price is  "+price);
                    }while (cursor.moveToNext());
                }
                cursor.close();
            }
        });

运行程序查看Log


使用SQL操作数据库

添加数据

db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[]{"The Vinci Code", "Dan Brown", "456", "16.96"});
 db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[]{"The Lost Symbol", "Dan Brown", "456", "19.95"});

更新数据

db.execSQL("update Book set price = ? where name =?",new String[]{"10.99","The Vinci Code"});

删除数据

db.execSQL("delete from Book where pages >?",new String[]{"500"});

查询数据

db.execSQL("select * from Book",null);


完整代码

public class MyDatabaseHelper extends SQLiteOpenHelper {
    private Context mContext;
    public static  final  String CREARE_BOOK = "create table Book ("//表名 Book
            + "id integer primary key autoincrement,"// primary 主键  autoincrement ID自动增长
            +"author text,"//text 文本
            +"price real,"// real 浮点型
            +"pages integer,"
            +"name text )";

    public static  final  String CREARE_CATEGORY = "create table Category ("//表名 Category
            + "id integer primary key autoincrement,"// primary 主键  autoincrement ID自动增长
            +"category_name text,"//text 文本
            +"category_code integer)";

    /**
     *
     * @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);
        this.mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREARE_BOOK);
        db.execSQL(CREARE_CATEGORY);
        Toast.makeText(mContext,"Create succeed",Toast.LENGTH_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int olderVersion, int newVersion) {
        //如果存在Book表或 Category表 先删除掉
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }
}
public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
        AppCompatButton createDatabase = findViewById(R.id.create_database);
        //创建数据库
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dbHelper.getWritableDatabase();
            }
        });
        //添加数据
        AppCompatButton addData = findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                //添加第一条数据
                values.put("name","The Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages",456);
                values.put("price",16.96);
                //插入第一条数据
                //Book 表名
                // null 用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL ,一般不用,传入null就行
                //values ContentValues对象,提供一系列的put方法重载,用于向ContentValues中添加数据
                db.insert("Book",null,values);
                values.clear();
                //添加第二条数据
                values.put("name","The Lost Symbol");
                values.put("author","Dan Brown");
                values.put("pages",510);
                values.put("price",19.95);
                //插入第二条数据
                db.insert("Book",null,values);
                //SQL
//                db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[]{"The Vinci Code", "Dan Brown", "456", "16.96"});
//                db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[]{"The Lost Symbol", "Dan Brown", "456", "19.95"});
            }
        });
        //更新数据
        AppCompatButton updateData = findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price",10.99);
                //第三个参数  对应SQL语句的where部分,表示更新所有name等于?的行,而?是一个占位符,
                // 可以通过第四个参数提供一个字符串数组为第三个参数中的每个占位符指定相应的内容
                //将名字是The Vinci Code的这本书价格改为10.99
                db.update("Book",values,"name=?",new String[]{"The Vinci Code"});
                //SQL
               // db.execSQL("update Book set price = ? where name =?",new String[]{"10.99","The Vinci Code"});
            }
        });
        //删除数据
        AppCompatButton deleteData = findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //第二三个参数用于约束删除某一行 或是某几行的数据,不指定的话就是删除所有行。
                //删除pages超过500 的书
                SQLiteDatabase db = dbHelper.getWritableDatabase();db.delete("Book","pages >?",new String[]{"500"});
                //SQL
                //db.execSQL("delete from Book where pages >?",new String[]{"500"});
            }
        });
        //查询数据
        AppCompatButton queryBitton = findViewById(R.id.query_data);
        queryBitton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 第一个参数   表名
                // 第二个参数  指定去哪查询,不指定查询所有
                //第三四个参数 约束查询某一行或某几行数据,不指定查询所有行
                //第五个参数  指定需要去group by的列,不指定表示不对查询结果进行group by
                //第六个参数  用于对group by之后的数据进行过滤,不指定表示不进行过滤
                //第七个参数  指定查询结果的排序方式,不指定表示默认排序
                Cursor cursor = db.query("Book",null,null,null,null,null,null);
                //将数据的指针移动到第一行的位置
                if (cursor.moveToFirst()){
                    do {
                        //getColumnIndex() 取到某一列在表中对应的位置索引,
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        Log.d("MainActivity","book name is  "+name);
                        Log.d("MainActivity","book author is  "+author);
                        Log.d("MainActivity","book pages is  "+pages);
                        Log.d("MainActivity","book price is  "+price);
                    }while (cursor.moveToNext());
                }
                cursor.close();
                //SQL
               // db.execSQL("select * from Book",null);
            }
        });
    }
}

使用LitePal操作数据库

配置LitePal

LitePal采用对象关系映射(ORM),什么是对象关系映射呢?我们使用的编程语言是面向对象语言,而使用的数据库则是关系型数据库,那么将面向对象语言和面向关系的数据库之间建立一种映射关系,就是对象关系映射。它赋予我们一个强大的功能,可以用面向对象的思维来操作数据库,而不用再和SQL语句打交道了。

引入LitePal

 implementation 'org.litepal.android:core:1.6.1'

配置litepal.xml文件,右击app/src/main目录,创建assets目录,在assets下新建litepal.xml文件

编辑litepal.xml文件

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="BookStore"></dbname>
    <version value="1"></version>
    <list></list>
</litepal>

<list>指定所有的映射模型

在AndroidMnifest.xml中配置LitePalApplication

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zsp.databasetest">

    <application
        android:name="org.litepal.LitePalApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

创建和升级数据库

创建Book类

public class Book {
    private  int id;
    private String author;
    private double price;
    private int pages;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getPages() {
        return pages;
    }

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

    public String getName() {
        return name;
    }

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


修改litepal.xml 代码

<list>
        <mapping class = "com.zsp.litepaltest.Book"></mapping>
</list>

修改MainActivity代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton createDatabase = findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LitePal.getDatabase();
            }
        });
    }
}

运行程序


数据库创建成功

使用LitePal更新数据库

向Book中添加press列,修改Book类中的代码,添加如下代码

private String press;
    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = press;
    }

再创建Category表

public class Category {
    private int id;
    private String categoryName;
    private String categoryCode;

    public void setId(int id) {
        this.id = id;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public void setCategoryCode(String categoryCode) {
        this.categoryCode = categoryCode;
    }
}


修改litepal.xml版本号加1,添加一个新的模型类

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="BookStore"></dbname>
    <version value="2"></version>
    <list>
        <!--完整包名-->
        <mapping class = "com.zsp.litepaltest.Book"></mapping>
        <mapping class = "com.zsp.litepaltest.Category"></mapping>
    </list>
</litepal>

点击create database按钮运行程序


新增了Category表,Book表中增加了press列,LitePal还自动帮我们保留之前表中的所有数据,这样就不用担心数据丢失的问题了。使用db.execSQL("drop table if exists Book");先删除之前的数据库,容易造成之前的数据丢失。

使用LitePal添加数据

只需要创建出模型类的实例,在将所有要存储的数据设置好,在调用一些save()就好了。LitePal进行表管理操作时不需要模型类有任何继承结构,但是进行CRUD操作就必须要继承自DataSuooort类。

修改Book类

public class Book extends DataSupport{
    private  int id;
    private String author;
    private double price;
    private int pages;
    private String name;

    private String press;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getPages() {
        return pages;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = press;
    }
}

MainActivity添加代码

AppCompatButton addData = findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Book book = new Book();
                book.setName("The Da Vinci Code");
                book.setAuthor("Dan Brown");
                book.setPages(454);
                book.setPrice(16.96);
                book.setPress("Unknow");
                book.save();
            }
        });

运行程序


数据添加成功。

使用LitePal更新数据

常用的几种更新数据的方式

最简单的一种更新方式就是对已存储的对象重新设置,然后调用save()方法即可。

什么是已存储对象,对LitePal来说,对象是否已存储就是根据调用model.isSaved()方法的结果来判断的,返回true表示已存储,返回false表示未存储。只有在两种情况下model.isSaved()返回true,一种是已经调用过model.save()方法添加数据,此时model会被认为是已存储对象,另一种情况是model对象是通过LitePal提供的API查出来的,由于数据是从数据库查到的的对象,也会被认为是已存储对象。

第一种情况

MainActivity中添加代码

AppCompatButton upData = findViewById(R.id.update_data);
        upData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //调用model.save()方法
                Book book = new Book();
                book.setName("The Lost Symbol ");
                book.setAuthor("Dan Brown");
                book.setPages(510);
                book.setPrice(19.95);
                book.setPress("Unknow");
                book.save();
                book.setPrice(10.99);
                book.save();
            }
        });

先添加了一条数据,调用setPrice()方法将价格进行修改,在调用save()方法。此时LitePal会发现当前的Book对象是已存储的,因此不会再向数据库中去添加一条数据,而是会直接更新当前的数据。

运行程序


数据更新成功。但这种更新方式只能对已存储的对象进行操作,限制性打,更为灵巧的方式为。

AppCompatButton upData = findViewById(R.id.update_data);
        upData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //调用model.save()方法
                Book book = new Book();
                book.setPrice(14.95);
                book.setPress("Anthor");
                book.updateAll("name = ? and author = ?","The Lost Symbol","Dan Brown");
            }
        });


在使用updateAll()方法时,当想把一个字段的值设为默认值时,不能使用上面的方式来set数据,不会更新。LitePal提供了setToDefault()方法,比如可以这么写

 Book book = new Book();
                book.setToDefault("pages");
                book.updateAll();


使用LitePal删除数据

修改MainActivity中代码

 AppCompatButton deleteData = findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DataSupport.deleteAll(Book.class,"price<?","15");
            }
        });

运行程序

数据删除成功。

使用LitePal查询数据

AppCompatButton queryButton = findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                List<Book> books = DataSupport.findAll(Book.class);
                for (Book book:books){
                    Log.d("MainActivity","book name is "+book.getName());
                    Log.d("MainActivity","book author is "+book.getAuthor());
                    Log.d("MainActivity","book pages is "+book.getPages());
                    Log.d("MainActivity","book price is "+book.getPrice());
                    Log.d("MainActivity","book press is "+book.getPress());
                }
            }
        });

运行程序


查询成功。

其他非常常用的查询API

                //查询Book表中的第一条数据
                Book firstBook = DataSupport.findFirst(Book.class);
                //查询Book表中的最后一条数据
                Book lastBook = DataSupport.findLast(Book.class);
                //只查name 和 author
                List<Book> books1 = DataSupport.select("name","author").find(Book.class);
                //只查页数大于400的
                List<Book> books2 = DataSupport.where("pages > ?","400").find(Book.class);
                //按指定结果排序 按价格从高到低 desc 降序  asc或不写升序
                List<Book> books3 = DataSupport.order("price desc").find(Book.class);
                //指定查询结果的数量 只查表中的前三条
                List<Book> books4 = DataSupport.limit(3).find(Book.class);
                //指定查询结果的偏移量 查询表中的第二、三、四条数据
                List<Book> books5 = DataSupport.limit(3).offset(1).find(Book.class);

                //查询表中低11到20条满足页数大于400这个条件的name,author,和pages这三个数据,并将查询结果按升序排列
                List<Book> books6 = DataSupport
                        .select("name","author","pages")
                        .where("pages >?","400")
                        .order("pages")
                        .limit(10)
                        .offset(10)
                        .find(Book.class);
                //LitePal支持原生查询 得到cursor后利用循环取出来
                Cursor cursor = DataSupport.findBySQL("select * from Book where pages > ? and price < ?","400","20");

完整代码

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.AppCompatButton;
import android.util.Log;
import android.view.View;

import org.litepal.LitePal;
import org.litepal.crud.DataSupport;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton createDatabase = findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LitePal.getDatabase();
            }
        });
        AppCompatButton addData = findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Book book = new Book();
                book.setName("The Da Vinci Code");
                book.setAuthor("Dan Brown");
                book.setPages(454);
                book.setPrice(16.96);
                book.setPress("Unknow");
                book.save();
            }
        });
        AppCompatButton upData = findViewById(R.id.update_data);
        upData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //调用model.save()方法
                Book book = new Book();
//                book.setName("The Lost Symbol ");
//                book.setAuthor("Dan Brown");
//                book.setPages(510);
//                book.setPrice(19.95);
//                book.setPress("Unknow");
//                book.save();
//                book.setPrice(10.99);
//                book.save();
                book.setPrice(14.95);
                book.setPress("Anthor");
                book.updateAll("name = ? and author = ?","The Lost Symbol","Dan Brown");
            }
        });
        AppCompatButton deleteData = findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DataSupport.deleteAll(Book.class,"price<?","15");
            }
        });
        AppCompatButton queryButton = findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                List<Book> books = DataSupport.findAll(Book.class);
                for (Book book:books){
                    Log.d("MainActivity","book name is "+book.getName());
                    Log.d("MainActivity","book author is "+book.getAuthor());
                    Log.d("MainActivity","book pages is "+book.getPages());
                    Log.d("MainActivity","book price is "+book.getPrice());
                    Log.d("MainActivity","book press is "+book.getPress());
                }
            }
        });
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值