博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据持久化的几种方法——首选项+内部存储+外部存储+数据库
阅读量:6037 次
发布时间:2019-06-20

本文共 13943 字,大约阅读时间需要 46 分钟。

hot3.png

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

在res/xml下建preference的xml文件

用到的xml的tag: 
PreferenceScreen
 
PreferenceCategory
CheckBoxPreference
EditTextPreference
RingtonePreference
其中 
PreferenceScreen
中的内容显示在同一个界面里, 
PreferenceScreen
嵌入
PreferenceScreen
 可以放置一个入口进入另一个界面;
 
PreferenceCategory
对首选项内容进行分类(视觉上的,实际调用感觉没区别);
每个首选项都有一个键值
android:key
跟View的id类似的识别作用;
public   class   MyPrefAty   extends   PreferenceActivity   {    @Override   protected   void  onCreate ( Bundle  savedInstanceState )   {   super . onCreate ( savedInstanceState );    PreferenceManager  preferenceManager  =  getPreferenceManager ();  preferenceManager . setSharedPreferencesName ( "MySelfdefinePrefName" );   addPreferencesFromResource ( R . xml . myapppreferences );   } }

继承自  
PreferenceActivity
,从xml文件加载首选项界面,并且重命名该首选项的名称
用到的类:
PreferenceManager
用到的方法: 
getPreferenceManager
()
setSharedPreferencesName
(
"MySelfdefinePrefName"
)
addPreferencesFromResource
(
R
.
xml
.
myapppreferences
)
public   void  onClickDisplay ( View  view )   {   // SharedPreferences sharedPreferences = getSharedPreferences("com.example.administrator.mypreference_preferences", MODE_PRIVATE);   SharedPreferences  sharedPreferences  =  getSharedPreferences ( "MySelfdefinePrefName" ,  MODE_PRIVATE );   Toast . makeText ( getBaseContext (),  sharedPreferences . getString ( "editTextPref" ,   "" ),   Toast . LENGTH_SHORT ). show ();   }    public   void  onClickModify ( View  view )   {   //SharedPreferences sharedPreferences = getSharedPreferences("com.example.administrator.mypreference_preferences", MODE_PRIVATE);   SharedPreferences  sharedPreferences  =  getSharedPreferences ( "MySelfdefinePrefName" ,  MODE_PRIVATE );   SharedPreferences . Editor  editor  =  sharedPreferences . edit ();  editor . putString ( "editTextPref" ,   (( EditText )  findViewById ( R . id . txtString )). getText (). toString ());  editor . commit ();   }

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

2. 数据保存到内部存储

public class FileSave extends Activity {      EditText editText;      static final int READ_BLOCK_SIZE = 100;      @Override      protected void onCreate(Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      setContentView(R.layout.myfilesavelayout);      editText = (EditText) findViewById(R.id.edittextFile);      }      public void onClickLoad(View v) {      try {      FileInputStream fileInputStream = openFileInput("textfile.txt");      InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);      char[] inputBuffer = new char[READ_BLOCK_SIZE];      String s = "";      int charRead;      while ((charRead = inputStreamReader.read(inputBuffer)) > 0) {      String readString = String.copyValueOf(inputBuffer, 0, charRead);      s += readString;      }      editText.setText(s);      Toast.makeText(getBaseContext(), "File Load Successfully.", Toast.LENGTH_SHORT).show();      } catch (FileNotFoundException e) {      e.printStackTrace();      } catch (IOException e) {      e.printStackTrace();      }      }      public void onClickSave(View view) {      String string = editText.getText().toString();      try {      FileOutputStream fileOutputStream = openFileOutput("textfile.txt", MODE_WORLD_READABLE);      OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);      outputStreamWriter.write(string);      outputStreamWriter.flush();      outputStreamWriter.close();      Toast.makeText(getBaseContext(), "File Save Successfully", Toast.LENGTH_SHORT).show();      editText.setText("");      } catch (IOException e) {      e.printStackTrace();      }      }     }

用到的类:
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卡(外部存储)

public class SdSave extends Activity {      EditText editText;      @Override      protected void onCreate(Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      setContentView(R.layout.mysdlayout);      editText = (EditText) findViewById(R.id.SDedittextFile);      }      public void onClickSaveSD(View view) {      String string = editText.getText().toString();      try {      File sdCard = Environment.getExternalStorageDirectory();      File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");      directory.mkdir();      File file = new File(directory, "textfile.txt");      FileOutputStream fileOutputStream = new FileOutputStream(file);      OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);      outputStreamWriter.write(string);      outputStreamWriter.flush();       outputStreamWriter.close();      } catch (IOException e) {      e.printStackTrace();      }      Toast.makeText(getBaseContext(), "Save In SD successfully!", Toast.LENGTH_SHORT).show();      editText.setText("");      }      public void onClickLoadSD(View view) {      try {      File sdCard = Environment.getExternalStorageDirectory();      File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");      File file = new File(directory, "textfile.txt");      FileInputStream fileInputStream = new FileInputStream(file);      InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);      char[] inputBuffer = new char[100];      String s = "";      int charRead;      while ((charRead = inputStreamReader.read(inputBuffer)) > 0) {      String readString = String.copyValueOf(inputBuffer, 0, charRead);      s += readString;      inputBuffer = new char[100];      }      editText.setText(s);      } catch (FileNotFoundException e) {      e.printStackTrace();      } catch (IOException e) {      e.printStackTrace();      }      }     }

用到的类:
File
Environment
FileOutputStream
OutputStreamWriter
FileInputStream
InputStreamReader
用到的方法:
getExternalStorageDirectory
()
getAbsolutePath
()
mkdir
()
write
(
string
)
flush
()
close
()
read
(
inputBuffer
)
copyValueOf
(
inputBuffer
,
0
,
charRead
)
关键在于用 
getExternalStorageDirectory
()
和 
getAbsolutePath
()
获得SD卡完整的路径(还需加上自定义的文件夹名和文件名)

4.使用数据库

public class DBAdapter { static final String KEY_ROWID = "_id"; static final String KEY_NAME = "name"; static final String KEY_EMAIL = "email"; static final String TAG = "DBAdapter";  static final String DATABASE_NAME = "MyDB3"; static final String DATABASE_TABLE = "contacts"; static final int DATABASE_VERSON = 1;  static final String DATABASE_CREATE = "create table contacts (_id integer primary key autoincrement,name text not null,email text not null);";  final Context context;  DatabaseHelper DBHelper;  SQLiteDatabase db;  public DBAdapter(Context context){ this.context = context; DBHelper = new DatabaseHelper(context); }  private static class DatabaseHelper extends SQLiteOpenHelper{  DatabaseHelper(Context context){ super(context, DATABASE_NAME, null, DATABASE_VERSON); }  @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DATABASE_CREATE); }  @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG,"Upgrading database from version "+oldVersion+" to "+ newVersion + ",which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS contacts"); onCreate(db); }   }   public DBAdapter open() throws SQLException{ db = DBHelper.getWritableDatabase(); //db = DBHelper.getReadableDatabase(); return this; }  public void close(){ DBHelper.close(); }  public long inserContacts(String name,String email){ ContentValues initialValues = new ContentValues(); initialValues.put(KEY_NAME,name); initialValues.put(KEY_EMAIL, email); return db.insert(DATABASE_TABLE,null,initialValues); }  public boolean deleteContact(long rowId){ return db.delete(DATABASE_TABLE,KEY_ROWID+"="+rowId,null)>0; }  public Cursor getAllContacts(){ return db.query(DATABASE_TABLE,new String[]{KEY_ROWID,KEY_NAME,KEY_EMAIL},null,null,null,null,null); }  public Cursor getContact(long rowId) throws SQLException{ Cursor cursor = db.query(true,DATABASE_TABLE,new String[]{KEY_ROWID,KEY_NAME,KEY_EMAIL},KEY_ROWID +"="+rowId,null,null,null,null,null); if (cursor!=null) cursor.moveToFirst(); return cursor; }  public boolean updateContact(long rowId,String name,String email){ ContentValues args = new ContentValues(); args.put(KEY_NAME,name); args.put(KEY_EMAIL,email); return db.update(DATABASE_TABLE,args,KEY_ROWID+"="+rowId,null)>0; }}

概述:创建一个辅助类来封装访问数据的复杂性(即方法)
用到的类:
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()就会被调用

编程方式使用数据库——

public class MainActivity extends Activity { DBAdapter dbAdapter; TextView textView;  @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);  textView = (TextView) findViewById(R.id.showInfo); dbAdapter = new DBAdapter(this);   try { dbAdapter.open(); } catch (SQLException e) { e.printStackTrace(); } long id = dbAdapter.inserContacts("Li XiaoMing","997654321@qq.com"); id = dbAdapter.inserContacts("Bruce","lixiaoming@gmail.com"); dbAdapter.close();  }  public void ShowAllcontacts(View view) { try { dbAdapter.open(); Cursor cursor = dbAdapter.getAllContacts(); String s = "";  if (cursor.moveToFirst()) { do { s += "id: " + cursor.getString(0) + " Name: " + cursor.getString(1) + " Email: " + cursor.getString(2) + "\n"; } while (cursor.moveToNext());  textView.setText(s); } dbAdapter.close(); } catch (SQLException e) { e.printStackTrace(); } }  public void ShowOneContact(View view) {  EditText editText = (EditText) findViewById(R.id.edittext_id); int id = Integer.parseInt(editText.getText().toString()); //   Toast.makeText(getBaseContext(),Integer.toString(id),Toast.LENGTH_SHORT).show();  try { dbAdapter.open(); Cursor cursor = dbAdapter.getContact(id); if (cursor.moveToFirst()) textView.setText("id: " + cursor.getString(0) + " Name: " + cursor.getString(1) + " Email: " + cursor.getString(2) + "\n"); else Toast.makeText(getBaseContext(), "Contact Not Found", Toast.LENGTH_SHORT).show(); } catch (SQLException e) { e.printStackTrace(); } dbAdapter.close();  }  public void UpdateContact(View view) { EditText editText = (EditText) findViewById(R.id.edittext_id); int id = Integer.parseInt(editText.getText().toString());  try { dbAdapter.open(); } catch (SQLException e) { e.printStackTrace(); } if (dbAdapter.updateContact(id, "Charley", "12332@outook.com")) Toast.makeText(getBaseContext(), "update Success", Toast.LENGTH_SHORT).show(); else Toast.makeText(getBaseContext(), "update failure", Toast.LENGTH_SHORT).show(); dbAdapter.close();  }  public void DeleteContact(View view) { EditText editText = (EditText) findViewById(R.id.edittext_id); int id = Integer.parseInt(editText.getText().toString());  try { dbAdapter.open(); } catch (SQLException e) { e.printStackTrace(); }  if (dbAdapter.deleteContact(id)) Toast.makeText(getBaseContext(), "Delete Success", Toast.LENGTH_SHORT).show(); else Toast.makeText(getBaseContext(), "Delete failure", Toast.LENGTH_SHORT).show();  dbAdapter.close(); }}

用到的类:
Cursor
DBAdapter(自定义的类)
用到的方法:
moveToFirst
()
moveToNext
()
getString
(
)
分析:使用时主要使用自定义的
DBAdapter
类进行处理数据,其中
Cursor
作为检索返回的数据的类型(类似一个数组集合)
以上的方法的数据库是在运行的时候被创建的,但有时程序可能需要使用现有的数据库或者导入预创建好的数据库。
那么,如何使用于创建好的数据库——
首先,介绍一个可以用来查看和编辑SQLite数据库的软件——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文件夹

代码:

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);  textView = (TextView) findViewById(R.id.showInfo); dbAdapter = new DBAdapter(this);  try { String destPath = "/data/data/" + getPackageName() + "/databases"; Toast.makeText(getBaseContext(), destPath, Toast.LENGTH_SHORT).show(); File file = new File(destPath); if (!file.exists()) { file.mkdirs(); file.createNewFile(); CopyDB(getBaseContext().getAssets().open("test2"), new FileOutputStream(destPath + "/MyDB3")); }  } catch (IOException e) { e.printStackTrace(); }  }   public void CopyDB(InputStream inputStream, OutputStream outputStream) throws IOException { byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } Toast.makeText(getBaseContext(), "Copy Success", Toast.LENGTH_SHORT).show(); inputStream.close(); outputStream.close(); }

用到的类:
File
FileOutputStream
InputStream
用到的方法: 
getPackageName
()
mkdirs
()
createNewFile
()
write
(
buffer
,
0
,
length
)
分析: 将assets里的DB文件拷贝到内部存储的databases文件夹里;DB文件至多只会被拷贝一次,因为是在判断databases文件夹是否存在之后才进行拷贝,避免重复覆盖DB数据。

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

你可能感兴趣的文章
make
查看>>
项目经理需了解的技术
查看>>
给包文件增加注释
查看>>
聚合查询, 分组查询,F查询,Q查询
查看>>
python代码-leetcode1 两数相加
查看>>
padding和margin的区别和作用及各种场合出现的bug
查看>>
Java开发中的23种设计模式详解(转)
查看>>
App测试方法总结
查看>>
分享职场心得《3》
查看>>
ModeBusRtu概述
查看>>
学习之路-现代密码学基础-001
查看>>
缓存遇到的数据过滤与分页问题
查看>>
实验05博客园总结
查看>>
(转)shell中括号的特殊用法 linux if多条件判断
查看>>
zabbix监控多tomcat实例
查看>>
CSS定宽居中的实现方案
查看>>
Elasticsearch5.x 升级
查看>>
vue中嵌套页面(iframe)
查看>>
[古怪问题] Marshal.GetActiveObject 在管理员模式下无法正常运行
查看>>
1600802047 android 第三次作业(音乐播放器)
查看>>