Li huaming himiOriginal, reprinted must be explicitly noted:
Reprinted from[Heimi gamedev block]Link: http://www.himigame.com/android-game/327.html
Many kids shoes say that after my code is run, clicking home or back will cause a program exception. If you have encountered this, you certainly haven't carefully read the himi blog, in article 19th, himi specifically wrote about the causes and solutions of these errors. I have added my remarks on this blog, and my provincial children's shoes are always confused. Please click here to contact us for further reading:
[Android game development 19th] (required) surfaceview Running Mechanism explanation-analyze back and home buttons and switch to the background to handle exceptions!
There are four Storage Methods Commonly Used in Android for storing game data. Here I will give you a brief introduction first:
1. sharedpreference
This storage method is used to save simple data. Its name is a configuration-type storage method and is not suitable for storing large data;
2. File Storage (fileinputstream/fileoutputstream)
This storage method is suitable for storing and using games and can store large amounts of data, because it is easier for children to accept than SQLite, this method not only stores data in the system, but also saves the data to the sdcard;
3. SQLite
This storage method is suitable for storing and using games. It can store large amounts of data and store its own data in a file system or database, you can also store your own data in the SQLite database or the data in the sdcard;
4. contentprovider (not recommended for game storage)
This method is not recommended for game storage because it not only stores large data, but also supports data exchange between multiple programs !!! However, since the game is basically unable to access external application data, I will not explain this method. If you are interested, you can go to Baidu and Google to learn it;
The above is a simple overview of several common storage methods. The following describes the advantages and disadvantages of each storage method and the implementation and notes of each storage method in detail!
Next I will first introduce the first storage method:
Storage Method:Sharedpreference
Advantages: simple, convenient, and suitable for quick storage of simple data
Disadvantages: 1. The number of stored files can only be used in the same package, not between different packages!
2. By default, data is stored in the system path/data/COM. himi/. No method for storing the data on the SD card is found.
Summary: in fact, this storage method is just like its name. It is convenient, but it is only suitable for storing simple data!
Main. xml:
<? XML version = "1.0" encoding = "UTF-8"?> <Br/> <linearlayout xmlns: Android = "http://schemas.android.com/apk/res/android" <br/> Android: Orientation = "vertical" Android: layout_width = "fill_parent" <br/> Android: layout_height = "fill_parent"> <br/> <textview Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" Android: text = "save data exercise! "<Br/> Android: textsize =" 20sp "Android: textcolor =" # ff0000 "Android: id = "@ + ID/TV _title"/> <br/> <textview Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" Android: TEXT = "Enter the Account"/> <br/> <edittext Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" Android: id = "@ + ID/edittext_login" <br/> Android: text = ""> </edittext> <br/> <textview Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" Android: text = "enter the password"/> <br/> <edittext Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" Android: Id = "@ + ID/edittext_password" <br/> Android: TEXT = ""> </edittext> <br/> <button Android: Id = "@ + ID/button_save" Android: layout_width = "wrap_content" <br/> Android: layout_height = "wrap_content" Android: text = "save"> </button> <br/> <button Android: Id = "@ + ID/button_load" Android: layout_width = "wrap_content" <br/> Android: layout_height = "wrap_content" Android: text = "retrieve data" <br/> Android: visibility = "invisible"> </button> <br/> </linearlayout>
The reason why we put the XML file first is that the sharedpreference and file storage (fileinputstream/fileoutputstream) introduced in this article share this XML, which is very simple: Two textviews, two editviews, and two buttons, I will not talk about it here;
The code implementation and detailed explanation of sharedpreference are as follows:
/** <Br/> * @ author himi <br/> * @ save method: sharedpreference <br/> * @ Note: sharedpreference can be used across packages. Thank you for reminding me of the kids shoes on the second floor! <Br/> * @ operation mode: context. mode_private: the new content overwrites the original content. <br/> * context. mode_append: after the new content is appended to the original content <br/> * context. mode_world_readable: allows other applications to read data. <br/> * context. mode_world_writeable: allows other applications to write data and overwrites the original data. <Br/> */<br/> public class mainactivity extends activity implements onclicklistener {<br/> private edittext et_login, et_password; <br/> private button btn_save; <br/> private textview TV _title; <br/> private sharedpreferences sp; <br/> @ override <br/> Public void oncreate (bundle savedinstancestate) {<br/> super. oncreate (savedinstancestate); <br/> getwindow (). setflags (windowmanager. layoutparams. Flag_fullscreen, <br/> windowmanager. layoutparams. flag_fullscreen); <br/> This. requestwindowfeature (window. feature_no_title); <br/> setcontentview (R. layout. main); <br/> btn_save = (button) findviewbyid (R. id. button_save); <br/> btn_save.setonclicklistener (this); <br/> et_login = (edittext) findviewbyid (R. id. edittext_login); <br/> et_password = (edittext) findviewbyid (R. id. edittext_password); <br/> TV _title = (textview) findviewbyid (R. id. TV _title); <br/> // here we call getsharedpreferences () to instantiate a sharedpreferences. <br/> // The second parameter indicates: operation Mode (as explained above) <br/> sp = getsharedpreferences ("setting_himi", mode_private ); <br/>/* <br/> * the following code reads the previous data when the program is started, <br/> * Of course, we have not saved any data, so we cannot find it !! <Br/> * if no value is found, a parameter value is returned by default. You can see the meaning of the method below! <Br/> */<br/> sp. getstring ("login", ""); <br/> // getstring () is similar to a hash table. A key is a Volue, <br/> // if the corresponding first parameter (key) cannot be found for this method, the second parameter will be used as the return value of this key <br/> et_login.settext (sp. getstring ("login", ""); <br/> et_password.settext (sp. getstring ("password", ""); <br/>}< br/> @ override <br/> Public void onclick (view V) {<br/> If (V = btn_save) {<br/> If (et_login.gettext (). tostring (). equals ("") <br/> TV _title.se Ttext ("enter an account! "); <Br/> else if (et_password.gettext (). tostring (). Equals (" ") <br/> TV _title.settext (" enter the password! "); <Br/> else {<br/> sp. edit () <br/>. putstring ("login", et_login.gettext (). tostring () <br/>. putstring ("password", et_password.gettext (). tostring () <br/>. commit (); <br/> // from sp. edit () starts to enter the editing status until commit () is submitted! <Br/> TV _title.settext ("saved successfully! You can re-open this program and test whether the data has been saved! "+ <Br/>"/N (or under the 'file explorer 'window-data-data-com.himi path "+ <br/>" existence "+"' setting _ himi. XML ') "); <br/>}< br/>}
The comments in the Code are clear and simple.
Storage Method: file storage outputstream/inputstream
Advantages: 1. Suitable for game storage and large data storage;
2. Not only can it be stored in the system, but also in the SD card!
Summary: if you are not familiar with SQL, this method is the most suitable.
/** <Br/> * @ author himi <br/> * @ save mode: stream data stream mode <br/> * @ Note 1: by default, files created using the openfileoutput method can only be used by applications called by them. <br/> * Other applications cannot read the files. If you need to share data with different applications; <br/> * @ NOTE 2: Because the Internal flash memory of Android OS is limited, it is suitable for storing a small amount of data. Of course, we also have solutions, <br/> * It is to save the data in SD, so that you can proceed. I will explain it later! <Br/> * @ 1: When fileoutputstream is called, the specified file does not exist. Android automatically creates the file. <Br/> * by default, the original file content will be overwritten during writing, if you want to attach the newly written content <br/> * to the content of the original file, you can specify the mode as context. mode_append. <Br/> * @ remind 2 to handle the initialization process! There are comments in the code! Be sure to take a closer look! <Br/> * @ Note 3 here I will introduce two methods: one is to write/read the original file stream, <br/> * Another method is to use the data stream to wrap the file stream for write/read operations. In fact, the data stream is used for packaging operations. <br/> * The reason is: more write/read operations are supported after packaging. For example, file stream writing does not support <br/> * writeutf (string Str), but is supported after packaging with data. <Br/> * @ operation mode: context. mode_private: the new content overwrites the original content. <br/> * context. mode_append: after the new content is appended to the original content <br/> * context. mode_world_readable: allows other applications to read data. <br/> * context. mode_world_writeable: allows other applications to write data and overwrites the original data. <Br/> */<br/> public class mainactivity extends activity implements onclicklistener {<br/> private edittext et_login, et_password; <br/> private button btn_save; <br/> private textview TV _title; <br/> private fileoutputstream Fos; <br/> private fileinputstream FD; <br/> private dataoutputstream DOS; <br/> private datainputstream DIS; <br/> @ override <br/> Public void oncreate (bundle savedinstancestate ){ <Br/> string temp = NULL; <br/> super. oncreate (savedinstancestate); <br/> getwindow (). setflags (windowmanager. layoutparams. flag_fullscreen, <br/> windowmanager. layoutparams. flag_fullscreen); <br/> This. requestwindowfeature (window. feature_no_title); <br/> setcontentview (R. layout. main); <br/> btn_save = (button) findviewbyid (R. id. button_save); <br/> btn_save.setonclicklistener (this); <br/> et_login = (editte XT) findviewbyid (R. id. edittext_login); <br/> et_password = (edittext) findviewbyid (R. id. edittext_password); <br/> TV _title = (textview) findviewbyid (R. id. TV _title); <br/> try {<br/> // openfileinput does not return the default value if it is not found in sharedpreference <br/> // The getsharedpreferences method, <br/> // if the data file cannot be found, an exception is reported, so closing the stream in finally is especially important !!! <Br/> If (this. openfileinput ("Save. himi ")! = NULL) {<br/> // -------------- reading with file alone --------------- <br/> // FS = This. openfileinput ("Save. himi "); <br/> // bytearrayoutputstream bytearray = new <br/> // bytearrayoutputstream (); <br/> // byte [] buffer = new byte [1024]; <br/> // int Len = 0; <br/> // while (LEN = Fi. read (buffer)> 0) {<br/> // bytearray. write (buffer, 0, Len); <br/> //} <br/> // temp = bytearray. tostring (); <br/> //-------- ------ Read method after data stream packaging ------------ <br/> FCM = This. openfileinput ("Save. himi "); // Note 1 <br/> Dis = new datainputstream (FCM); <br/> et_login.settext (DIS. readutf (); <br/> et_password.settext (DIS. readutf (); <br/> // read the stored data when the program is started. <br/> // read the stored data in sequence; for example, when we write data <br/> // The string type first written, we also need to read the string type first, one-to-one correspondence! <Br/>}< br/>} catch (filenotfoundexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>} catch (ioexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>}finally {<br/> // close the stream in finally! If the data cannot be found, an exception occurs. We can also disable the data. <br/> try {<br/> If (this. openfileinput ("Save. himi ")! = NULL) {<br/> // you need to determine the value here, because the two streams will not be instantiated if they cannot be found. <Br/> // since it is not instantiated, call close to close it. "Null Pointer" is definitely abnormal !!! <Br/> FCM. close (); <br/>}< br/>} catch (filenotfoundexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>} catch (ioexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>}< br/> @ override <br/> Public void onclick (view V) {<br/> If (environment. getexternalstoragestate ()! = NULL) {<br/> // This method is used to test whether the terminal has an sdcard! <Br/> log. V ("himi", "SD card available"); <br/>}< br/> If (V = btn_save) {<br/> If (et_login.gettext (). tostring (). equals ("") <br/> TV _title.settext ("enter your account! "); <Br/> else if (et_password.gettext (). tostring (). Equals (" ") <br/> TV _title.settext (" enter the password! "); <Br/> else {<br/> try {<br/> // ------ writing with file alone ------------ <br/> // Fos = new fileoutputstream (f); <br/> // FOS. write (et_login.gettext (). tostring (). getbytes (); <br/> // FOS. write (et_password.gettext (). tostring (). getbytes (); <br/> // ------ data packaging and Writing Method -------------- <br/> Fos = This. openfileoutput ("Save. himi ", mode_private); // Note 2 <br/> dos = new dataoutputstream (FOS); <br/> dos. writeutf (et_logi N. gettext (). tostring (); <br/> dos. writeutf (et_password.gettext (). tostring (); <br/> TV _title.settext ("saved successfully! You can re-open this program. The test is "+ <br/>" no data has been saved! /N (or in the 'file explorer '"+ <br/>" window-under the data-data-com.himi-files path "+ <br/>" whether 'Save. himi') "); <br/>} catch (filenotfoundexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>} catch (ioexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>}finally {<br/> // close the stream in finally so that we can close the stream even if there is an exception in try; <br/> try {<br/> dos. close (); <br/> FOS. close (); <br/>}catch (ioexception e) {<br/> // todo auto-generated Catch Block <br/> E. printstacktrace (); <br/>}< br/>}
The above code implements two stream forms to complete writing and reading. Here, why do we use data stream for packaging? In fact, it is not just to get more operations, the most important thing is convenience and efficiency. For example, when you use file to read data, it is obviously complicated. It also extracts all the data at a time, which is not convenient for data processing!
The following points are emphasized:
1: at the beginning of the access to the data, we will remind the children's shoes again that this is different from the sharedpreference acquisition method. The sharedpreference acquisition method can get a default value, but what you get is a file and you can open it directly. Once there is no exception, the Exception Processing and finally processing must be done properly.
2. in fact, when we started to use data packaging, we found that characters were garbled during the reading of the written strings. We checked the API and found that, the API specifies that the encoding in the UTF-8 format must be written when writing a string, but I don't know what's going on. --If the kids shoes encounter this problem, I will give you a solution, that is, when writing data, we should not use dataoutputstream for packaging, but use outputstreamwriter, because you can set the encoding in the constructed code!
Outputstreamwriter OSW = new outputstreamwriter (FCM, "UTF-8 ");
String content = encodingutils. getstring (buffer, "UTF-8"); this can also transcode the character array!
This write is certainly the character of the UTF-8 encoding,
The following describes how to store our data into the SD card through outputstream/inputstream!
In fact, if we put our data into the SD card, we need to modify the code in two ways:
Note: You must have an SD card! There are two ways to create an SD card in the previous article;
1. Check whether the SD card is installed;
Second, modify the read location(Note 1)
Fiis = This. openfileinput ("Save. himi"); // there is no path here, the path is under the default data-data-com.himi-files
Replace it with the path of our SD card:
File Path = new file ("/sdcard/himi/Save. himi"); // create a file directory path
FS = new fileinputstream (PATH); input path
Third:Modify the write location(Note 2)
Fos = This. openfileoutput ("Save. himi", mode_private); this is the default path and needs to be modified,
Note: If the modification is made, you must modify the finally statement accordingly;
NOTE: If it is a system path, Android will create a file by default if this file is not available! But when we put the SD card, we need to create our own directory path and file!
If (environment. getexternalstoragestate ()! = NULL) {// This method is used to test whether the terminal has sdcard! <Br/> log. V ("himi", "SD card"); <br/> File Path = new file ("/sdcard/himi "); // create a directory <br/> file F = new file ("/sdcard/himi/save. himi "); // create a file <br/> If (! Path. exists () {// If the directory does not exist, false is returned. <br/> path. mkdirs (); // create a directory <br/>}< br/> If (! F. exists () {// if the file does not exist, false is returned. <br/> F. createnewfile (); // create a file <br/>}< br/> Fos = new fileoutputstream (f); // Save the data to the SD card <br/>}
Fourth: because we want to write data to the SD card, we need to declare the permission in the configuration file!
Androidmainfest. xml
<? XML version = "1.0" encoding = "UTF-8"?> <Br/> <manifest xmlns: Android = "http://schemas.android.com/apk/res/android" <br/> package = "com. himi "<br/> Android: versioncode =" 1 "<br/> Android: versionname =" 1.0 "> <br/> <application Android: icon = "@ drawable/icon" Android: Label = "@ string/app_name"> <br/> <activity Android: Name = ". mainactivity "<br/> Android: Label =" @ string/app_name "> <br/> <intent-filter> <br/> <action Android: Name =" android. intent. action. main "/> <br/> <category Android: Name =" android. intent. category. launcher "/> <br/> </intent-filter> <br/> </activity> <br/> </Application> <br/> <uses-Permission Android: name = "android. permission. write_external_storage "/> <br/> <uses-SDK Android: minsdkversion =" 4 "/> <br/> </manifest>
That's it ~
<Uses-Permission Android: Name = "android. Permission. write_external_storage"/>
In order to let everyone see the location, the entire XML is put for reference;
When creating a path and a file, we will check whether the exists () method exists in the SD card. if it already exists, we will not create it, in this way, you can avoid creating a new file and path when writing data again,
In fact, when starting the program, we can determine that if this file is not available, we can directly create a file, which is optimized. I mainly want you to introduce and learn, other methods are simplified and optimized, and other methods are left to you,
OK. Here we will introduce how SQLite stores data and operates on the data! I hope you will continue to pay attention to it!
(We recommend that you subscribe to this blog, because our update speed is very fast ~ Wahaha)
Source code: http://www.himigame.com/android-game/327.html
In the new year, James wishes everyone a smooth career, good health, and happy family in the new year!
Previous project: