当前位置:   article > 正文

数据持久化的几种方法——首选项+内部存储+外部存储+数据库

首选项的数据持久化后是放在哪里

1. 使用Preference来保存首选项数据

在res/xml下建preference的xml文件

  1. <? xml version = "1.0" encoding = "utf-8" ?>
  2. <PreferenceScreen xmlns:android = "http://schemas.android.com/apk/res/android" >
  3. <PreferenceCategory android:title = "Category One" >
  4. <CheckBoxPreference
  5. android:defaultValue = "false"
  6. android:key = "checkboxpref"
  7. android:summary = "True or False"
  8. android:title = "CheckBox" />
  9. </PreferenceCategory>
  10. <PreferenceCategory android:title = "Category Two" >
  11. <EditTextPreference
  12. android:defaultValue = "[Enter a string here]"
  13. android:key = "editTextPref"
  14. android:summary = "Enter a string"
  15. android:title = "Edit Text" />
  16. <RingtonePreference
  17. android:key = "ringtonepref"
  18. android:summary = "select a ringtone"
  19. android:title = "Ringtones" />
  20. <PreferenceScreen
  21. android:key = "SecondPrefScreen"
  22. android:summary = "Click here to go to the second preference screen"
  23. android:title = "Second prefernce Screen" >
  24. <EditTextPreference
  25. android:key = "secondedittext"
  26. android:summary = "Enter a key"
  27. android:title = "Edit Text(Second Screen)" />
  28. </PreferenceScreen>
  29. </PreferenceCategory>
  30. </PreferenceScreen>



用到的xml的tag:  PreferenceScreen   PreferenceCategory CheckBoxPreference EditTextPreference RingtonePreference
其中  PreferenceScreen 中的内容显示在同一个界面里,  PreferenceScreen 嵌入 PreferenceScreen  可以放置一个入口进入另一个界面;
  PreferenceCategory 对首选项内容进行分类(视觉上的,实际调用感觉没区别);
每个首选项都有一个键值 android:key 跟View的id类似的识别作用;

  1. public class MyPrefAty extends PreferenceActivity {
  2. @Override
  3. protected void onCreate ( Bundle savedInstanceState ) {
  4. super . onCreate ( savedInstanceState );
  5. PreferenceManager preferenceManager = getPreferenceManager ();
  6. preferenceManager . setSharedPreferencesName ( "MySelfdefinePrefName" );
  7. addPreferencesFromResource ( R . xml . myapppreferences );
  8. }
  9. }



继承自   PreferenceActivity ,从xml文件加载首选项界面,并且重命名该首选项的名称
用到的类: PreferenceManager
用到的方法:  getPreferenceManager () setSharedPreferencesName ( "MySelfdefinePrefName" ) addPreferencesFromResource ( R . xml . myapppreferences )

  1. public void onClickDisplay ( View view ) {
  2. // SharedPreferences sharedPreferences = getSharedPreferences("com.example.administrator.mypreference_preferences", MODE_PRIVATE);
  3. SharedPreferences sharedPreferences = getSharedPreferences ( "MySelfdefinePrefName" , MODE_PRIVATE );
  4. Toast . makeText ( getBaseContext (), sharedPreferences . getString ( "editTextPref" , "" ), Toast . LENGTH_SHORT ). show ();
  5. }
  6. public void onClickModify ( View view ) {
  7. //SharedPreferences sharedPreferences = getSharedPreferences("com.example.administrator.mypreference_preferences", MODE_PRIVATE);
  8. SharedPreferences sharedPreferences = getSharedPreferences ( "MySelfdefinePrefName" , MODE_PRIVATE );
  9. SharedPreferences . Editor editor = sharedPreferences . edit ();
  10. editor . putString ( "editTextPref" , (( EditText ) findViewById ( R . id . txtString )). getText (). toString ());
  11. editor . commit ();
  12. }



用到的类:  SharedPreferences SharedPreferences . Editor
用到的方法: getSharedPreferences ( "MySelfdefinePrefName" , MODE_PRIVATE ) edit () putString() commit ()
关键: getSharedPreferences() 的第一个参数是对应首选项的xml的名称,默认是 “包名+_preferencens”,由此获得相应的首选项。修改首选项中的值 需要用到  SharedPreferences . Editor


2. 数据保存到内部存储


  1. public class FileSave extends Activity {
  2. EditText editText;
  3. static final int READ_BLOCK_SIZE = 100;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.myfilesavelayout);
  8. editText = (EditText) findViewById(R.id.edittextFile);
  9. }
  10. public void onClickLoad(View v) {
  11. try {
  12. FileInputStream fileInputStream = openFileInput("textfile.txt");
  13. InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
  14. char[] inputBuffer = new char[READ_BLOCK_SIZE];
  15. String s = "";
  16. int charRead;
  17. while ((charRead = inputStreamReader.read(inputBuffer)) > 0) {
  18. String readString = String.copyValueOf(inputBuffer, 0, charRead);
  19. s += readString;
  20. }
  21. editText.setText(s);
  22. Toast.makeText(getBaseContext(), "File Load Successfully.", Toast.LENGTH_SHORT).show();
  23. } catch (FileNotFoundException e) {
  24. e.printStackTrace();
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. public void onClickSave(View view) {
  30. String string = editText.getText().toString();
  31. try {
  32. FileOutputStream fileOutputStream = openFileOutput("textfile.txt", MODE_WORLD_READABLE);
  33. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
  34. outputStreamWriter.write(string);
  35. outputStreamWriter.flush();
  36. outputStreamWriter.close();
  37. Toast.makeText(getBaseContext(), "File Save Successfully", Toast.LENGTH_SHORT).show();
  38. editText.setText("");
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. }



用到的类: FileInputStream InputStreamReader FileOutputStream OutputStreamWriter
用到的方法: openFileInput ( "textfile.txt" ) read ( inputBuffer ) copyValueOf ( inputBuffer , 0 , charRead ) openFileOutput ( "textfile.txt" , MODE_WORLD_READABLE ) write ( string ) flush () close ()

关键点: openFileOutput ( "textfile.txt" , MODE_WORLD_READABLE )  和  openFileInput ( "textfile.txt" ) 都是使用相对路径,即内部存储的路径,只需要自定义文件名。


3. 保存数据到SD卡(外部存储)


  1. public class SdSave extends Activity {
  2. EditText editText;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.mysdlayout);
  7. editText = (EditText) findViewById(R.id.SDedittextFile);
  8. }
  9. public void onClickSaveSD(View view) {
  10. String string = editText.getText().toString();
  11. try {
  12. File sdCard = Environment.getExternalStorageDirectory();
  13. File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");
  14. directory.mkdir();
  15. File file = new File(directory, "textfile.txt");
  16. FileOutputStream fileOutputStream = new FileOutputStream(file);
  17. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
  18. outputStreamWriter.write(string);
  19. outputStreamWriter.flush();
  20. outputStreamWriter.close();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. Toast.makeText(getBaseContext(), "Save In SD successfully!", Toast.LENGTH_SHORT).show();
  25. editText.setText("");
  26. }
  27. public void onClickLoadSD(View view) {
  28. try {
  29. File sdCard = Environment.getExternalStorageDirectory();
  30. File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");
  31. File file = new File(directory, "textfile.txt");
  32. FileInputStream fileInputStream = new FileInputStream(file);
  33. InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
  34. char[] inputBuffer = new char[100];
  35. String s = "";
  36. int charRead;
  37. while ((charRead = inputStreamReader.read(inputBuffer)) > 0) {
  38. String readString = String.copyValueOf(inputBuffer, 0, charRead);
  39. s += readString;
  40. inputBuffer = new char[100];
  41. }
  42. editText.setText(s);
  43. } catch (FileNotFoundException e) {
  44. e.printStackTrace();
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }



用到的类: File Environment FileOutputStream OutputStreamWriter FileInputStream InputStreamReader
用到的方法: getExternalStorageDirectory () getAbsolutePath () mkdir () write ( string ) flush () close () read ( inputBuffer ) copyValueOf ( inputBuffer , 0 , charRead )

关键在于用  getExternalStorageDirectory () 和  getAbsolutePath () 获得SD卡完整的路径(还需加上自定义的文件夹名和文件名)


4.使用数据库

  1. public class DBAdapter {
  2. static final String KEY_ROWID = "_id";
  3. static final String KEY_NAME = "name";
  4. static final String KEY_EMAIL = "email";
  5. static final String TAG = "DBAdapter";
  6. static final String DATABASE_NAME = "MyDB3";
  7. static final String DATABASE_TABLE = "contacts";
  8. static final int DATABASE_VERSON = 1;
  9. static final String DATABASE_CREATE = "create table contacts (_id integer primary key autoincrement,name text not null,email text not null);";
  10. final Context context;
  11. DatabaseHelper DBHelper;
  12. SQLiteDatabase db;
  13. public DBAdapter(Context context){
  14. this.context = context;
  15. DBHelper = new DatabaseHelper(context);
  16. }
  17. private static class DatabaseHelper extends SQLiteOpenHelper{
  18. DatabaseHelper(Context context){
  19. super(context, DATABASE_NAME, null, DATABASE_VERSON);
  20. }
  21. @Override
  22. public void onCreate(SQLiteDatabase db) {
  23. db.execSQL(DATABASE_CREATE);
  24. }
  25. @Override
  26. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  27. Log.w(TAG,"Upgrading database from version "+oldVersion+" to "+ newVersion + ",which will destroy all old data");
  28. db.execSQL("DROP TABLE IF EXISTS contacts");
  29. onCreate(db);
  30. }
  31. }
  32. public DBAdapter open() throws SQLException{
  33. db = DBHelper.getWritableDatabase();
  34. //db = DBHelper.getReadableDatabase();
  35. return this;
  36. }
  37. public void close(){
  38. DBHelper.close();
  39. }
  40. public long inserContacts(String name,String email){
  41. ContentValues initialValues = new ContentValues();
  42. initialValues.put(KEY_NAME,name);
  43. initialValues.put(KEY_EMAIL, email);
  44. return db.insert(DATABASE_TABLE,null,initialValues);
  45. }
  46. public boolean deleteContact(long rowId){
  47. return db.delete(DATABASE_TABLE,KEY_ROWID+"="+rowId,null)>0;
  48. }
  49. public Cursor getAllContacts(){
  50. return db.query(DATABASE_TABLE,new String[]{KEY_ROWID,KEY_NAME,KEY_EMAIL},null,null,null,null,null);
  51. }
  52. public Cursor getContact(long rowId) throws SQLException{
  53. Cursor cursor = db.query(true,DATABASE_TABLE,new String[]{KEY_ROWID,KEY_NAME,KEY_EMAIL},KEY_ROWID +"="+rowId,null,null,null,null,null);
  54. if (cursor!=null)
  55. cursor.moveToFirst();
  56. return cursor;
  57. }
  58. public boolean updateContact(long rowId,String name,String email){
  59. ContentValues args = new ContentValues();
  60. args.put(KEY_NAME,name);
  61. args.put(KEY_EMAIL,email);
  62. return db.update(DATABASE_TABLE,args,KEY_ROWID+"="+rowId,null)>0;
  63. }
  64. }





概述:创建一个辅助类来封装访问数据的复杂性(即方法)
用到的类: SQLiteDatabase SQLiteOpenHelper ContentValues Cursor
用到的方法: onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ) getWritableDatabase () close () put ( KEY_NAME , name ) insert ( DATABASE_TABLE , null , initialValues ) delete ( DATABASE_TABLE , KEY_ROWID + "=" + rowId , null ) query ( DATABASE_TABLE , new String []{ KEY_ROWID , KEY_NAME , KEY_EMAIL }, null , null , null , null , null ) update ( DATABASE_TABLE , args , KEY_ROWID + "=" + rowId , null )

核心:   SQLiteOpenHelper 是个安卓SQL的辅助类,用来处理数据库的创建和版本管理 ,需要重写它的onCreate()和onUpgrade()方法。 onCreate()在所需数据库不存在的时候被调用来创建一个新的数据库, onUpgrade()在数据库需要升级的时候被调用,取决于数据库的版本号码变化。(e.g. 将上面代码中的 DATABASE_VERSON从1改到2 ,再次运行程序的时候onUpgrade()就会被调用


编程方式使用数据库——

  1. public class MainActivity extends Activity {
  2. DBAdapter dbAdapter;
  3. TextView textView;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. textView = (TextView) findViewById(R.id.showInfo);
  9. dbAdapter = new DBAdapter(this);
  10. try {
  11. dbAdapter.open();
  12. } catch (SQLException e) {
  13. e.printStackTrace();
  14. }
  15. long id = dbAdapter.inserContacts("Li XiaoMing","997654321@qq.com");
  16. id = dbAdapter.inserContacts("Bruce","lixiaoming@gmail.com");
  17. dbAdapter.close();
  18. }
  19. public void ShowAllcontacts(View view) {
  20. try {
  21. dbAdapter.open();
  22. Cursor cursor = dbAdapter.getAllContacts();
  23. String s = "";
  24. if (cursor.moveToFirst()) {
  25. do {
  26. s += "id: " + cursor.getString(0) + " Name: " + cursor.getString(1) + " Email: " + cursor.getString(2) + "\n";
  27. } while (cursor.moveToNext());
  28. textView.setText(s);
  29. }
  30. dbAdapter.close();
  31. } catch (SQLException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. public void ShowOneContact(View view) {
  36. EditText editText = (EditText) findViewById(R.id.edittext_id);
  37. int id = Integer.parseInt(editText.getText().toString());
  38. // Toast.makeText(getBaseContext(),Integer.toString(id),Toast.LENGTH_SHORT).show();
  39. try {
  40. dbAdapter.open();
  41. Cursor cursor = dbAdapter.getContact(id);
  42. if (cursor.moveToFirst())
  43. textView.setText("id: " + cursor.getString(0) + " Name: " + cursor.getString(1) + " Email: " + cursor.getString(2) + "\n");
  44. else
  45. Toast.makeText(getBaseContext(), "Contact Not Found", Toast.LENGTH_SHORT).show();
  46. } catch (SQLException e) {
  47. e.printStackTrace();
  48. }
  49. dbAdapter.close();
  50. }
  51. public void UpdateContact(View view) {
  52. EditText editText = (EditText) findViewById(R.id.edittext_id);
  53. int id = Integer.parseInt(editText.getText().toString());
  54. try {
  55. dbAdapter.open();
  56. } catch (SQLException e) {
  57. e.printStackTrace();
  58. }
  59. if (dbAdapter.updateContact(id, "Charley", "12332@outook.com"))
  60. Toast.makeText(getBaseContext(), "update Success", Toast.LENGTH_SHORT).show();
  61. else
  62. Toast.makeText(getBaseContext(), "update failure", Toast.LENGTH_SHORT).show();
  63. dbAdapter.close();
  64. }
  65. public void DeleteContact(View view) {
  66. EditText editText = (EditText) findViewById(R.id.edittext_id);
  67. int id = Integer.parseInt(editText.getText().toString());
  68. try {
  69. dbAdapter.open();
  70. } catch (SQLException e) {
  71. e.printStackTrace();
  72. }
  73. if (dbAdapter.deleteContact(id))
  74. Toast.makeText(getBaseContext(), "Delete Success", Toast.LENGTH_SHORT).show();
  75. else
  76. Toast.makeText(getBaseContext(), "Delete failure", Toast.LENGTH_SHORT).show();
  77. dbAdapter.close();
  78. }
  79. }




用到的类: Cursor DBAdapter(自定义的类)
用到的方法: moveToFirst () moveToNext () getString ( )

分析:使用时主要使用自定义的 DBAdapter 类进行处理数据,其中 Cursor 作为检索返回的数据的类型(类似一个数组集合)


以上的方法的数据库是在运行的时候被创建的,但有时程序可能需要使用现有的数据库或者导入预创建好的数据库。
那么,如何使用于创建好的数据库——
首先,介绍一个可以用来查看和编辑SQLite数据库的软件——sqlitebrowser—— http://https://github.com/sqlitebrowser/sqlitebrowser
接着,简单介绍一下安卓使用的 SQLite 数据库的特殊之处:

如果在程序中创建一个DB,导出后使用进行sqlitebrowser查看——发现,有2个额外的表 android_metadata和sqlite_squence



其中android_metadata用来定义使用的语言,可以删除(虽然有的博客说不行,但我亲测是可以的)



sqlite_squence似乎是来记录主要表的信息(项的数量),并且无法删除

    

      

易出Bug的地方:
sqlitebrowser新建一个DB,会将版本默认为是0,在上面的代码中 DATABASE_VERSON 设置为1,因此如果直接导入新建的这个DB,会出现错误(程序崩溃...查了好久的bug...)
在以下的地方进行修改版本号


将DB文件放入\app\src\main\assets文件夹


代码:


  1. protected void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. setContentView(R.layout.activity_main);
  4. textView = (TextView) findViewById(R.id.showInfo);
  5. dbAdapter = new DBAdapter(this);
  6. try {
  7. String destPath = "/data/data/" + getPackageName() + "/databases";
  8. Toast.makeText(getBaseContext(), destPath, Toast.LENGTH_SHORT).show();
  9. File file = new File(destPath);
  10. if (!file.exists()) {
  11. file.mkdirs();
  12. file.createNewFile();
  13. CopyDB(getBaseContext().getAssets().open("test2"), new FileOutputStream(destPath + "/MyDB3"));
  14. }
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. public void CopyDB(InputStream inputStream, OutputStream outputStream) throws IOException {
  20. byte[] buffer = new byte[1024];
  21. int length;
  22. while ((length = inputStream.read(buffer)) > 0) {
  23. outputStream.write(buffer, 0, length);
  24. }
  25. Toast.makeText(getBaseContext(), "Copy Success", Toast.LENGTH_SHORT).show();
  26. inputStream.close();
  27. outputStream.close();
  28. }



用到的类: File FileOutputStream InputStream
用到的方法:  getPackageName () mkdirs () createNewFile () write ( buffer , 0 , length )

分析: 将assets里的DB文件拷贝到内部存储的databases文件夹里;DB文件至多只会被拷贝一次,因为是在判断databases文件夹是否存在之后才进行拷贝,避免重复覆盖DB数据。

转载于:https://my.oschina.net/Bruce370/blog/419907

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/288497
推荐阅读
相关标签
  

闽ICP备14008679号