Instantaneous data refers to data that is stored in memory that may be lost due to program shutdown or other causes of memory being recycled. This is absolutely intolerable for some critical data information, and no one wants to have just sent out a microblog, refreshing it. So how can you ensure that some critical data is not lost? This requires the use of data persistence technology.
Introduction to Persistent technologies
Data persistence means that the instantaneous data in memory is saved to the storage device, ensuring that the data is not lost even when the phone or computer shuts down. The data stored in memory is instantaneous, while the data stored in the storage device is persisted, and persistence provides a mechanism for transforming the data between the transient state and the persistent state.
The Android system offers three ways to simply implement data persistence, namely file storage, Sharedpreference storage, and database storage. Of course, in addition to these three ways, you can also save the data in the phone's SD card, but the use of files, sharedpreference or database to save the data is relatively simpler, and more than the data saved in the SD card will be more secure.
File storage
File storage is the most basic form of data storage in Android, it does not do any formatting of the stored content, all the data is stored intact in the file, so it is more suitable for storing some simple text data or binary data. If you want to use file storage to save some more complex text data, you need to define a set of your own formatting specifications, which makes it easier to re-parse the data from the file later.
Here is an example of storing data in a file and reading data from a file with the following code:
The layout file is simple enough to contain only a single EditText control:
<linearlayout xmlns:android="Http://schemas.android.com/apk/res/android" Android:layout_width="Match_parent"android:layout_height="Match_parent" > <EditTextandroid:id= "@+id/edit"android:layout_width=" Match_parent "android:layout_height="wrap_content "android:hint=" Type something here " /> </linearlayout>
The main code is also implemented in the Mainactivity class:
Public class mainactivity extends Activity { PrivateEditText edit;@Override protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (R.layout.activity_main); Edit = (EditText) Findviewbyid (R.id.edit); String inputtext = load ();if(! Textutils.isempty (Inputtext)) {The Textutils.isempty () method is used when making a non-null judgment on a string, which is a very useful method for judging two null values at once. This method returns True when the passed-in string equals null or is equal to an empty string, so that we do not need to judge the two null values individually, and then use the logical operators to join them. Edit.settext (Inputtext); Edit.setselection (Inputtext.length ()); Toast.maketext ( This,"Restoring succeeded", Toast.length_short). Show (); } }@Override protected void OnDestroy() {Super. OnDestroy (); String Inputtext = Edit.gettext (). toString (); Save (Inputtext); }//Store data in a file Public void Save(String Inputtext) {FileOutputStream out =NULL; BufferedWriter writer =NULL;Try{out = Openfileoutput ("Data", context.mode_private);The //context class provides a openfileoutput () method that can be used to store data in the specified file. This method receives two parameters, the first parameter is the file name, the name is used in the creation of the document, note that the file name specified here can not contain the path, because all the files are stored by default to/data/data/<package name>/files/ Directory. The second parameter is the mode of operation of the file, there are two main modes to choose from, Mode_private and Mode_append. Where mode_private is the default mode of operation, indicating that when the same file name is specified, the content written will overwrite the contents of the original file, and mode_append means that if the file already exists, it will append content to the file and create a new file if it does not exist. In fact, there are two other modes of operation of the file, Mode_world_readable and Mode_world_writeable, both of which allow other applications to read and write to the files in our program, but because these two modes are too dangerous, Vulnerability to application vulnerabilities is now deprecated in Android version 4.2. writer =NewBufferedWriter (NewOutputStreamWriter (out)); Writer.write (Inputtext); }Catch(IOException e) {E.printstacktrace (); }finally{Try{if(Writer! =NULL) {writer.close (); } }Catch(IOException e) {E.printstacktrace (); } } }//Read data from the file PublicStringLoad() {FileInputStream in =NULL; BufferedReader reader =NULL; StringBuilder content =NewStringBuilder ();Try{in = Openfileinput ("Data");The //context class also provides a Openfileinput () method for reading data from a file. This method is simpler than openfileoutput (), it takes only one parameter, that is, the name of the file to be read, and then the system automatically loads the file into the/data/data//files/directory and returns a FileInputStream object. This object can then be read from the Java stream by the way it is obtained. Reader =NewBufferedReader (NewInputStreamReader (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 (); } } }returnContent.tostring (); }}
Sharedpreferences Storage
Sharedpreferences is the way to store data using key-value pairs. That is, when you save a piece of data, you need to give the data a corresponding key, so that when the data can be read by this key to the corresponding value to be taken out. And Sharedpreferences also supports a variety of different data type storage, if the stored data type is integer, then the data read is an integral type, the stored data is a string, the data read is still a string.
Storing data in a sharedpreferences
To use Sharedpreferences to store data, you first need to get to the Sharedpreferences object. There are three main methods available in Android to get Sharedpreferences objects.
- The Getsharedpreferences () method in the context class
This method receives two parameters, the first parameter is used to specify the name of the Sharedpreferences file, and if the specified file does not exist, one is created, and the sharedpreferences file is stored in the/data/data//shared_prefs/ Directory. The second parameter specifies the mode of operation, and there are two main modes to choose from, Mode_private and mode_multi_process. Mode_private is still the default mode of operation, and the direct incoming 0 effect is the same, indicating that only the current application can read and write to this sharedpreferences file. Mode_multi_process is typically used to read and write to the same sharedpreferences file in multiple processes. Similarly, both the mode_world_readable and mode_world_writeable models have been deprecated in Android version 4.2.
- The Getpreferences () method in the Activity class
This method is similar to the Getsharedpreferences () method in the context, but it only receives an operation mode parameter, because using this method automatically takes the currently active class name as the sharedpreferences filename.
- The Getdefaultsharedpreferences () method in the Preferencemanager class
This is a static method that receives a context parameter and automatically uses the current application's package name as a prefix to name the sharedpreferences file.
After getting the Sharedpreferences object, we can begin to store data in the Sharedpreferences file, which can be divided into three steps.
- Call the edit () method of the Sharedpreferences object to get a Sharedpreferences.editor object.
- Add data to the Sharedpreferences.editor object, such as adding a Boolean data using the Putboolean method, adding a string using the Putstring () method, and so on.
- The commit () method is called to commit the data that was added, thus completing the data store operation.
Reading data from the Sharedpreferences
- The Sharedpreferences object provides a series of get methods for reading stored data, each of which corresponds to the
- Sharedpreferences. A put method in editor, such as reading a Boolean data using the Getboolean () method, reads a string using the GetString () method. These get methods receive two parameters, the first parameter is the key, the key used to pass in the stored data can get the corresponding value, the second parameter is the default value, that is, when the incoming key cannot find the corresponding value, the default value will be returned.
Sharedpreferences storage is a lot simpler and easier to store than text storage, and there are many applications, such as the preference settings in many applications that use sharedpreferences technology.
SQLite is a lightweight relational database that works very fast, takes up less resources, and typically requires only hundreds of K of memory, making it ideal for use on mobile devices. SQLite not only supports the standard SQL syntax, but also follows the acid transaction of the database, so you can quickly get on the floor with SQLite as long as you've used other relational databases before. And SQLite than the general database is much simpler, it does not even need to set the user name and password can be used. Android is the very powerful database embedded in the system, so that the local persistence of the function has a qualitative leap.
Create a database
Android in order to make it easier for us to manage the database, we specifically provide a Sqliteopenhelper helper class that allows you to create and upgrade the database very simply by using this class. Since there are good things to use directly, we naturally have to try, and I will introduce the basic usage of sqliteopenhelper.
First you need to know that Sqliteopenhelper is an abstract class, which means that if we want to use it, we need to create our own helper class to inherit it. There are two abstract methods in Sqliteopenhelper, namely OnCreate () and Onupgrade (), we must rewrite the two methods in our helper class, and then implement the logic of creating and upgrading the database separately in these two methods.
There are also two very important example methods in Sqliteopenhelper, Getreadabledatabase () and Getwritabledatabase (). Both of these methods can create or open an existing database (open directly if the database already exists, otherwise create a new database) and return an object that can read and write to the database. The difference is that when the database is not writable (such as disk space is full) the object returned by the Getreadabledatabase () method will open the database in a read-only manner, and the Getwritabledatabase () method will have an exception.
There are two construction methods in Sqliteopenhelper that can be overridden, typically using a less-parametric construction method. This construction method receives four parameters, the first parameter is the context, this has nothing to say, must have it to operate the database. The second parameter is the database name, which is the name specified here when the database is created. The third parameter allows us to return a custom cursor when querying the data, usually passing null. The fourth parameter represents the version number of the current database and can be used to perform an upgrade operation on the database. Once the instance of Sqliteopenhelper is built, the getreadabledatabase () or Getwritabledatabase () method is called to create the database, and the database file is stored in the/data/data// The databases/directory. At this point, the overridden OnCreate () method is also executed, so there is usually some logic to create the table here.
Use the ADB shell to check the creation of databases and tables.
ADB is a debugging tool that comes with the Android SDK, which allows you to debug a phone or emulator connected directly to your computer. It is stored in the Platform-tools directory of the SDK, and if you want to use the tool on the command line, you need to configure its path to the environment variable first.
If you are using a Windows system, you can right-click my computer → properties → advanced → environment variables, then locate the path in the system variable and click Edit to configure the Platform-tools directory, as shown in 6.12.
If you are using a Linux system, you can edit the. bash_profile file under your home path, and configure the Platform-tools directory to go in, as shown in 6.13:
Once you have configured the environment variables, you can use the ADB tool. Open the command line interface and enter the ADB shell, which will go to the console of the device, as shown in 6.14.
Then use the CD command to go to the/data/data/com.example.databasetest/databases/directory and use the LS command to view the files in that directory, as shown in 6.15.
There are two database files in this directory, one is the bookstore.db that we created, and the other bookstore.db-journal is the temporary log file that is generated to allow the database to support transactions, typically the size of this file is 0 bytes.
Next we need to use the SQLite command to open the database, just type sqlite3, followed by the database name, 6.16.
At this point, the BOOKSTORE.DB database has been opened and the tables in this database can now be managed. First look at what tables are currently in the database, type the. Table command, as shown in 6.17.
As you can see, there are two tables in the database, and the Android_metadata table is automatically generated in each database, regardless of it, and the other book table is what we created in Mydatabasehelper. It is also possible to view their built-in statements by using the. Schema command, shown in 6.18.
This proves that the Bookstore.db database and the Book table have indeed been created successfully. After you type the. exit or. Quit command to exit the editing of the database, and then type the exit command to exit the device console.
Upgrade Database Add data
In fact, we can operate on the data is nothing more than four kinds, namely crud. Where C stands for Add (Create), R for Query (Retrieve), U for Update (updates), and D for delete. Each operation also corresponds to a SQL command, if you are familiar with the SQL language, you will know to add data when using INSERT, query data using SELECT, update data using update, delete data when deleting. But the level of developers is always uneven, not everyone can be very familiar with the SQL language, so Android also provides a series of auxiliary methods, so that in Android even if not to write SQL statements, can easily complete all crud operations. The
Getreadabledatabase () or Getwritabledatabase () method that calls Sqliteopenhelper can be used to create and upgrade databases, not only that, Both methods also return a Sqlitedatabase object, which enables CRUD operations on the data. An insert () method is provided in
Sqlitedatabase, which is dedicated to adding data. It receives three parameters, the first parameter is the table name, and we want to add the data to which table, where the name is passed in. The second parameter is used to automatically assign NULL to certain nullable columns without specifying the addition of data, which is generally not possible with this function, and can be passed directly to null. The third parameter is a Contentvalues object that provides a series of put () method overloads to add data to the contentvalues by simply passing in each column name in the table and the corresponding data to be added.
Example:
SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); // 开始组装第一条数据 values.put("name", "The Da Vinci Code"); values.put("author", "Dan Brown"); values.put("pages", 454); values.put("price", 16.96); 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); // 插入第二条数据
Update data
Sqlitedatabase also provides a very useful update () method for updating the data, this method receives four parameters, the first parameter and the Insert () method, is also the table name, where you specify to update which table data. The second parameter is the Contentvalues object, which is to assemble the updated data here. The third and fourth parameters are used to constrain the updating of data in a row or rows, and the default is to update all rows if not specified.
Example:
SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("price", 10.99); db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });
Here a Contentvalues object is built in the click event of the Update Data button, and only a set of data is assigned to it, stating that we just want to update the data for the price column to 10.99. Then call the Sqlitedatabase Update () method to perform the specific update operation, you can see that the third and fourth parameters are used here to specify which rows to update specifically. The third parameter corresponds to the where part of the SQL statement, which means to update all rows whose name equals? is a placeholder that can specify the appropriate content for each placeholder in the third parameter by providing a string array from the fourth argument. So the intent of the above code is to change the price of the book named the Da Vinci code to 10.99.
Delete data
Sqlitedatabase provides a delete () method specifically for deleting data, this method receives three parameters, the first parameter is still the table name, this has nothing to say, the second, the third parameter is used to constrain the deletion of a row or a few rows of data, If you do not specify, the default is to delete all rows.
Example:
SQLiteDatabase db = dbHelper.getWritableDatabase(); db.delete("Book", "page s > ?", new String[] { "500" });
Querying data
We all know that SQL is the full name of Structured query Language, translated into Chinese is structured query language. Its large function is reflected in the word "check", and "adding and deleting" is only a small part of the function.
A query () method is also provided in sqlitedatabase for querying the data. The parameters of this method are very complex, and the shortest method overload also requires passing in seven parameters. Let's take a look at the meanings of each of the seven parameters, the first parameter needless to say, and of course the table name, indicating which table we want to query the data from. The second parameter is used to specify which columns to query, and if not specified, all columns are queried by default. The third and fourth parameters are used to constrain the query of data for a row or rows, and the default is to query the data for all rows without specifying it. The fifth parameter specifies the column that needs to go to group by, without specifying a group by operation for the query result. The sixth parameter is used to further filter the data after group by, without specifying that it is not filtered. The seventh parameter specifies how the query results are sorted, and does not specify that the default sort is used. More detailed information can be found in the table below. Several other overloads of the query () method are in fact similar, you can study it yourself, here is no longer introduced.
Query () method parameters
corresponding SQL section
Describe
Table
From table_name
Specify the table name for the query
Columns
Select Column1, Column2
Specify the column name of the query
Selection
where column = value
Specify the WHERE constraint
Selectionargs-provides a specific value for a placeholder in the where
GroupBy
Group BY column
Specify columns that require GROUP by
Having
Having column = value
Further constraints on GROUP by results
By
Order by Column1, Column2
Specify how query results are sorted
Although the query () method has a lot of parameters, don't be afraid of it because we don't have to specify all the parameters for each query statement, and in most cases we just need to pass in a few parameters to complete the query operation. When the query () method is called, a cursor object is returned, and all data that is queried is removed from the object.
Example:
Sqlitedatabase db = Dbhelper.getwritabledatabase (); Querying all data in the Book table cursor cursor = db.query ("book", NULL, NULL, NULL, NULL, NULL, NULL); if (Cursor.movetofirst ()) {do {//Traverse cursor object, take out data and print 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 are" + pages); LOG.D ("Mainactivity", "book Price are" + price); } while (Cursor.movetonext ()); } cursor.close ();
As you can see, we first call the Sqlitedatabase query () method to query the data in the Click event of the Inquiry button. The query () method here is very simple, just use the first parameter to indicate that you want to query the Book table, after which the parameters are all null. This means that you want to query all the data in this table, although there is only one data left in this table. After the query, we get a cursor object, and then we call its Movetofirst () method to move the data pointer to the first row, and then into a loop to iterate through each row of data queried. In this loop, the cursor's Getcolumnindex () method can be used to obtain the corresponding position index of a column in a table, and then pass the index to the corresponding value method to get the data read from the database. We then use log to print out the data, so we can check to see if the reading has been completed successfully. Finally, don't forget to call the close () method to close the cursor.
Using SQL to manipulate databases
Use SQL directly to complete the CRUD operations you've learned in the previous sections:
Here's how to add data:
Db.execsql ("INSERT into book (name, author, pages, price) VALUES (?,?,?,?)",
New string[] {"The Da Vinci Code", "Dan Brown", "454", "16.96"});
Db.execsql ("INSERT into book (name, author, pages, price) VALUES (?,?,?,?)",
New string[] {"The Lost Symbol", "Dan Brown", "510", "19.95"});
Here's how to update your data:
Db.execsql ("update book Set price =?") WHERE name =? ", new string[] {" 10.99 "," The Da Vinci Code "});
Here's how to delete data:
Db.execsql ("Delete from book where pages >?", New string[] {"500"});
Here's how to query data:
Db.rawquery ("SELECT * from book", NULL);
As you can see, the Sqlitedatabase rawquery () method is called in addition to querying the data, and the other operations are the Execsql () method of the call.
Using transactions
The SQLite database is a transactional one, and the nature of the transaction ensures that a series of operations are either complete or none of them will be completed. So under what circumstances do you need to use the transaction? Imagine a scenario where, for example, you are making a transfer, the bank will deduct the amount of the transfer from your account before adding an equal amount to the recipient's account. Looks like there's no problem, does it? However, if the amount in your account has just been deducted, then due to some unusual causes of the other side of the collection failed, this part of the money is lost in thin air! Of course, the bank must have fully taken into account this situation, it will ensure that the operation of the deduction and collection is either successful or unsuccessful, and the technology used is of course the business.
Example:
Database db = Dbhelper.getwritabledatabase (); Db.begintransaction (); Open transaction try {db.delete ("book", NULL, NULL); if (true) {//throws an exception here manually, let the transaction fail throw new NullPointerException (); } contentvalues values = new Contentvalues (); Values.put ("name", "Game of Thrones"); Values.put ("Author", "George Martin"); Values.put ("pages", 720); Values.put ("Price", 20.85); Db.insert ("book", null, values); Db.settransactionsuccessful (); Transaction has executed successfully} catch (Exception e) {e.printstacktrace (); } finally {db.endtransaction ();//End Transaction}
The above code is the standard use of transactions in Android, first call Sqlitedatabase's BeginTransaction () method to open a transaction, and then execute the specific database operation in a code block of exception capture, when all the operations are complete, Calling Settransactionsuccessful () indicates that the transaction has executed successfully, and finally calls Endtransaction () in the finally code block to end the transaction. Note that we have manually thrown a nullpointerexception after the operation to delete the old data, so that the code to add the new data is not executed. However, due to the existence of a transaction, an exception in the middle will cause the failure of the transaction, when the old data should be deleted.
Best practices for upgrading a database
before we learned how to upgrade the database is very rude, in order to ensure that the database table is up-to-date, we simply removed the current table in the Onupgrade () method, and then forced to re-execute it again OnCreate () Method. This method can be used in the development phase of the product, but when the product is actually online, it will definitely not work. Imagine the following scenario, such as an app you've written that has been successfully launched and has a good download volume. Now because of the reason for adding new features, the database needs to be upgraded together, and then the user updates this version and discovers that the local data stored in the previous program is lost! Unfortunately, your user base may have lost more than half.
sounds scary, doesn't it say that you can't upgrade the database after the product is released? Of course not, in fact, only need to do some reasonable control, you can ensure that the database when upgrading the data is not lost.
Below we will learn how to implement such a function, you already know that each database version will correspond to a version number, when the specified database version number is greater than the current database version number, it will go into the Onupgrade () method to perform the update operation. It is necessary to give each version number its own changed content, and then in the Onupgrade () method to determine the current database version number, and then perform the corresponding changes.
Example:
@Override public void onupgrade ( Sqlitedatabase db, int oldversion, int newversion) {switch (oldversion) {case 1 : Db.execsql (create_category); case 2 : Db.execsql ( "ALTER TABLE book add column Category_ ID integer ""); default :}}
Please note that there is a very important detail here, and the end of each case in switch does not use break, why do you do this? This is to ensure that every database modification can be performed at the time of the cross-version upgrade. For example, the user is currently upgrading from the second version of the program to the third version of the program, then the logic in case 2 will be executed. If the user is directly from the first version of the program to upgrade to the third version of the program, then case 1 and the logic in case 2 will be executed. Using this approach to maintain a database upgrade, regardless of how the version is updated, ensures that the database's table structure is up-to-date and that the data in the table is not lost at all.
Read Guo Lin "first line of code" notes--The 6th data storage program, detailed persistence technology