当前位置:   article > 正文

Android数据存储——SharedPreferences及SDCard_sharedpreferences 保存到 sdcard

sharedpreferences 保存到 sdcard
一、数据存储选项:DataStorage ——Storage Options
1、SharedPreferences
Store privateprimitive data in key-value pairs.
保存简单的键值对数据。
2、InternalStorage
Store privatedata on the device memory.
在手机内存中保存不对外共享的信息。
3、ExternalStorage
Store public dataon the shared external storage.
在外部存储设备上保存公共的数据信息。主要指保存在SDCard上。
4、SQLiteDatabases
Store structureddata in a private database.
将结构化的数据保存进数据库。
5、NetworkConnection
Store data on theweb with your own network server.
将数据保存到自己的远程服务器上。
【备注:】
  • 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。 
  • 所以对于内部存储空间,我们要尽量避免使用。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。 
  • getFilesDir()获取你app的内部存储空间,相当于你的应用在内部存储上的根目录。
  • 最容易混淆的是外部存储,如果说pc上区分出外部存储和内部存储的话,那么自带的硬盘算是内部存储,U盘或者移动硬盘算是外部存储,因此我们很容易带着这样的理解去看待安卓手机,认为机身固有存储是内部存储,而扩展的SDCard卡是外部存储。比如Nexus 4有16G的内部存储,普通消费者可以这样理解,但是安卓的编程中不能,这16GB仍然是外部存储。

二、SharedPreferences:
(一)、概念:
   SharedPreferences是Android系统提供的一个通用的数据持久化框架,用于存储和读取key-value类型的原始基本数据类型对,目前支持string、int、long、float、boolean等基本类型的存储,对于自定义的对象数据类型,无法使用SharedPreferences来存储。
       SharedPreferences主要用于存储系统的配置信息。例如上次登录的用户名,上次最后设置的配置信息(如:是否打开音效、是否使用振动,小游戏的玩家积分等)。当再次启动程序后依然保持原有设置。SharedPreferences用键值对方式存储,方便写入和读取。

(二)、使用SharedPreferences的步骤:
1、获取SharedPreferences对象;
       SharedPreferences本身是一个接口,无法直接创建实例,通过Context的getSharedPreferences(Stringname, int  mode)方法来获取实例。
       该方法的第二个参数有以下三个值:【文件读写的操作模式
  • Context.MODE_PRIVATE: 指定该SharedPreferences的数据只能被本应用程序读、写;
  • Context.MODE_APPEND:新内容追加到原内容后;
  • Context.MODE_WORLD_READABLE: 指定 SharedPreferences数据能被其他应用程序读,但是不支持写;
  • Context.MODE_WORLD_WRITEABLE: 指定 SharedPreferences数据能被其他应用程序读、写。会覆盖原数据。 
  • 可以使用  +  连接这些权限
2、调用edit()方法获取SharedPreferences.Editor;
3、通过SharedPreferences.Editor接口提供的put()方法对SharedPreferences进行更新;
4、调用SharedPreferences.Editor的commit()方法,将更新提交到SharedPreferences中。

(三)、核心代码:
button_main_savedata.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                prefs = getSharedPreferences("myaccount", Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit();
                                editor.putInt("age", 38);
                                editor.putString("username", "wangxiangjun");
                                editor.putString("pwd", "123456");
                                editor.putString("username", "xiangjun");
                                editor.putString("age", "I'm 40 years old!");
                                editor.commit();
                        }
                });

                button_main_readdata.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                prefs = getSharedPreferences("myaccount", Context.MODE_PRIVATE);
                                String name = prefs.getString("username", "wxj");
                                String pwd = prefs.getString("pwd", "000");
                                int age = prefs.getInt("age", 20);
                                System.out.println("====>" + name + ":" + pwd + ":" + age);
                        }
                }); 


(四)、保存之后的SharedPreferences数据文件:
        SharedPreferences数据总是以xml格式保存在:/data/data/包名/shared_prefs目录下;
例如:
<?xmlversion='1.0' encoding='utf-8'standalone='yes' ?>
<map>
    <stringname="pwd">123456</string>
    <stringname="username">xiangjun</string>
    <int name="age">20</int>
</map>


(五)、SharedPreferences的设置Setting功能:
1、引入:

       手机中常有这样的设置页面,如果做这样的页面呢?是不是需要写一个复杂的布局文件,再写一堆事件监听来完成呢?

2、PreferenceActivity的简单用法:
    1)、步骤:
  • 将setting.xml文件放到res的xml目录下;
  • 将arrays.xml文件放到values目录下;
  • 写一个页面SettingActivity。
    2)、目录结构:

    3)、核心代码:
 //在SettingActivity中。不再需要setContentView(R.layout.activity_main)方法来加载布局了。 
 protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                // setContentView(R.layout.activity_main); addPreferencesFromResource(R.xml.setting);  
 //备注:This method was deprecated in API level 11. This function is not relevant for a modern fragment-based PreferenceActivity.这个方法在11版本以上就已经不推荐使用了。 } 


(六)、借助SharedPreferences实现黑名单管理:

1、示例代码:
  1. public class MainActivity extends Activity {
  2. <span style="font-family:Arial;"> </span>private ListView listView_main_blockList;
  3. <span style="font-family:Arial;"> </span>private EditText editText_main_number;
  4. <span style="font-family:Arial;"> </span>private TextView textView_main_emptyinfo;
  5. <span style="font-family:Arial;"> </span>private SharedPreferences prefs = null;
  6. <span style="font-family:Arial;"> </span>private Editor editor = null; private ArrayAdapter<String> adapter = null;
  7. <span style="font-family:Arial;"> </span> @Override protected void onCreate(Bundle savedInstanceState) {
  8. <span style="font-family:Arial;"> </span> super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
  9. <span style="font-family:Arial;"> </span>editText_main_number = (EditText) findViewById(R.id.editText_main_number);
  10. <span style="font-family:Arial;"> </span>listView_main_blockList = (ListView) findViewById(R.id.listView_main_blocklist);
  11. <span style="font-family:Arial;"> </span>textView_main_emptyinfo = (TextView) findViewById(R.id.text_main_emptyinfo);
  12. <span style="font-family:Arial;"> </span>prefs = getSharedPreferences("blocklist", Context.MODE_PRIVATE); editor = prefs.edit();
  13. <span style="font-family:Arial;"> </span> List<String> list = getBlocklist(); adapter = new ArrayAdapter<String>(this,
  14. <span style="font-family:Arial;"> </span>android.R.layout.simple_list_item_1, list); // 注意setEmptyView()的用法。当适配器为空的时候,设置ListView中的展示内容。
  15. <span style="font-family:Arial;"> </span>listView_main_blockList.setEmptyView(textView_main_emptyinfo);
  16. <span style="font-family:Arial;"> </span>listView_main_blockList.setAdapter(adapter); }
  17. <span style="font-family:Arial;"> </span>public void clickButton(View view) {
  18. <span style="font-family:Arial;"> </span>switch (view.getId()) {
  19. <span style="font-family:Arial;"> </span>case R.id.button_main_add:
  20. <span style="font-family:Arial;"> </span>String mpnumber = editText_main_number.getText().toString();
  21. <span style="font-family:Arial;"> </span>editor.putString(mpnumber, mpnumber);
  22. <span style="font-family:Arial;"> </span>editor.commit(); fillListView();
  23. <span style="font-family:Arial;"> </span>break;
  24. <span style="font-family:Arial;"> </span>case R.id.button_main_clear:
  25. <span style="font-family:Arial;"> </span>editor.clear();
  26. <span style="font-family:Arial;"> </span>editor.commit();
  27. <span style="font-family:Arial;"> </span> fillListView();
  28. <span style="font-family:Arial;"> </span>break;
  29. <span style="font-family:Arial;"> </span>default:
  30. <span style="font-family:Arial;"> </span> break; }
  31. <span style="font-family:Arial;"> </span> }
  32. <span style="font-family:Arial;"> </span>/* * 获取SharedPreferences中的全部数据,放到List集合中。形成适配器的数据源 */
  33. <span style="font-family:Arial;"> </span>private List<String> getBlocklist() { List<String> list = new ArrayList<String>();
  34. <span style="font-family:Arial;"> </span>try { Map<String, ?> map = prefs.getAll();
  35. <span style="font-family:Arial;"> </span> // 增强for循环,实现对Map集合的遍历
  36. <span style="font-family:Arial;"> </span>for (Map.Entry<String, ?> entry : map.entrySet()) {
  37. <span style="font-family:Arial;"> </span> list.add(entry.getKey());
  38. <span style="font-family:Arial;"> </span> }
  39. <span style="font-family:Arial;"> </span>return list;
  40. <span style="font-family:Arial;"> </span> } catch (Exception e) {
  41. <span style="font-family:Arial;"> </span>return null;
  42. <span style="font-family:Arial;"> </span>}
  43. <span style="font-family:Arial;"> </span>}
  44. <span style="font-family:Arial;"> </span> /* * 填充ListView控件,实现刷新显示数据的效果 */
  45. <span style="font-family:Arial;"> </span>private void fillListView() {
  46. <span style="font-family:Arial;"> </span>adapter.clear();
  47. <span style="font-family:Arial;"> </span>adapter.addAll(getBlocklist());
  48. <span style="font-family:Arial;"> </span> }
  49. <span style="font-family:Arial;"> </span> @Override
  50. <span style="font-family:Arial;"> </span>public boolean onCreateOptionsMenu(Menu menu) {
  51. <span style="font-family:Arial;"> </span>getMenuInflater().inflate(R.menu.main, menu);
  52. <span style="font-family:Arial;"> </span>return true;
  53. <span style="font-family:Arial;"> </span>}
  54. }


三、External Storage之SDCard操作:
(一)、引入:Android中提供了特有的两个方法来进行IO操作(openFileInput()和openFileOutput() ),但是毕竟手机内置存储空间很有限,为了更好地存储应用程序的大文件数据,需要读写SD卡上的文件。SD卡大大扩充了手机的存储能力。

(二)、读写SD卡的步骤:
1、先判断手机是否有sd卡;
        调用Environment的getExternalStorageState()方法判断手机是否插上sdcard。
2、获取sdcard的路径;
        调用Environment的getExternalStorageDirectory()方法来获取外部存储器的目录。
3、此外还可以获取SDCard可用磁盘空间的大小(借助StatFs类来实现);
4、清单文件中设置读写sdcard的权限;
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>   在sdcard中创建与删除文件的权限
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>   向sdcard写入权限
5、执行读写操作(基本IO流操作)。

【备注:】
Environment.getExternalStorageDirectory().getPath()来获取sdcard路径,如果您需要往sdcard中保存特定类型的内容,可以考虑使用Environment.getExternalStoragePublicDirectory(String type)方法,该方法可以返回特定类型的目录,目前支持如下类型:
  1. DIRECTORY_ALARMS //警报的铃声 
  2. DIRECTORY_DCIM //相机拍摄的图片和视频保存的位置 
  3. DIRECTORY_DOWNLOADS //下载文件保存的位置 
  4. DIRECTORY_MOVIES //电影保存的位置, 比如 通过google play下载的电影 
  5. DIRECTORY_MUSIC //音乐保存的位置 
  6. DIRECTORY_NOTIFICATIONS //通知音保存的位置 
  7. DIRECTORY_PICTURES//下载的图片保存的位置 
  8. DIRECTORY_PODCASTS //用于保存podcast(博客)的音频文件 
  9. DIRECTORY_RINGTONES//保存铃声的位置

【备注:】
        应用程序在运行的过程中如果需要向手机上保存数据,一般是把数据保存在SDcard中的。 大部分应用是直接在SDCard的根目录下创建一个文件夹,然后把数据保存在该文件夹中。 这样当该应用被卸载后,这些数据还保留在SDCard中,留下了垃圾数据。 如果你想让你的应用被卸载后,与该应用相关的数据也清除掉,该怎么办呢?

  • 通过Context.getExternalFilesDir()方法可以获取到 SDCard/Android/data/应用的包名/files/ 目录,一般放一些长时间保存的数据  【设置->应用->应用详情里面的”清除数据 Clear Data
  • 通过Context.getExternalCacheDir()方法可以获取到 SDCard/Android/data/应用包名/cache/目录,一般存放临时缓存数据            【设置->应用->应用详情里面的”清除缓存“ Clear Cache
  • 如果使用上面的方法,当你的应用在被用户卸载后,SDCard/Android/data/你的应用的包名/ 这个目录下的所有文件都会被删除,不会留下垃圾信息。
        而且上面二个目录分别对应 设置->应用->应用详情里面的”清除数据“与”清除缓存“选项。当然 如果要保存下载的内容,就不要放在以上目录下。



(三)、封装SDCard的工具类:SDCardHelper类
  
  1. public class SDCardHelper {
  2. private static String TAG = "SDCardHelper"; /* * 判断sdcard是否挂载 */
  3. public static boolean isSDCardMounted() {
  4. return Environment.getExternalStorageState().equals(
  5. Environment.MEDIA_MOUNTED);
  6. } /* * 获取sdcard绝对物理路径 */
  7. public static String getSDCardPath() {
  8. if (isSDCardMounted()) {
  9. return Environment.getExternalStorageDirectory()
  10. .getAbsolutePath();
  11. } else {
  12. return null;
  13. }
  14. } /* * 获取sdcard的全部的空间大小。返回MB字节 */
  15. public static long getSDCardSize() {
  16. if (isSDCardMounted()) {
  17. StatFs fs = new StatFs(getSDCardPath());
  18. long size = fs.getBlockSize();
  19. long count = fs.getBlockCount();
  20. return size * count / 1024 / 1024;
  21. }
  22. return 0;
  23. } /* * 获取sdcard的剩余的可用空间的大小。返回MB字节 */
  24. public static long getSDCardFreeSize() {
  25. if (isSDCardMounted()) {
  26. StatFs fs = new StatFs(getSDCardPath());
  27. long size = fs.getBlockSize();
  28. long count = fs.getAvailableBlocks();
  29. return size * count / 1024 / 1024;
  30. }
  31. return 0;
  32. } /* * 将文件(byte[])保存进sdcard指定的路径下 */
  33. public static boolean saveFileToSDCard(byte[] data, String dir,
  34. String filename) {
  35. BufferedOutputStream bos = null;
  36. if (isSDCardMounted()) {
  37. Log.i(TAG, "==isSDCardMounted==TRUE");
  38. File file = new File(getSDCardPath() + File.separator + dir);
  39. Log.i(TAG, "==file:" + file.toString() + file.exists());
  40. if (!file.exists()) {
  41. boolean flags = file.mkdirs();
  42. Log.i(TAG, "==创建文件夹:" + flags);
  43. }
  44. try {
  45. bos = new BufferedOutputStream(new FileOutputStream(
  46. new File(file, filename)));
  47. bos.write(data, 0, data.length);
  48. bos.flush();
  49. return true;
  50. } catch (Exception e) {
  51. e.printStackTrace();
  52. } finally {
  53. try {
  54. bos.close();
  55. } catch (IOException e) {
  56. e.printStackTrace();
  57. }
  58. }
  59. }
  60. return false;
  61. } /* * 已知文件的路径,从sdcard中获取到该文件,返回byte[] */
  62. public static byte[] loadFileFromSDCard(String filepath) {
  63. BufferedInputStream bis = null;
  64. ByteArrayOutputStream baos = null;
  65. if (isSDCardMounted()) {
  66. File file = new File(filepath);
  67. if (file.exists()) {
  68. try {
  69. baos = new ByteArrayOutputStream();
  70. bis = new BufferedInputStream(new FileInputStream(file));
  71. byte[] buffer = new byte[1024 * 8];
  72. int c = 0;
  73. while ((c = bis.read(buffer)) != -1) {
  74. baos.write(buffer, 0, c);
  75. baos.flush();
  76. }
  77. return baos.toByteArray();
  78. } catch (Exception e) {
  79. e.printStackTrace();
  80. } finally {
  81. try {
  82. if (bis != null) {
  83. bis.close();
  84. baos.close();
  85. }
  86. } catch (IOException e) {
  87. e.printStackTrace();
  88. }
  89. }
  90. }
  91. }
  92. return null;
  93. }
  94. }

(四)、案例: 
1、功能:点击按钮,实现从网络上访问图片,将图片保存进SDCard中。点击另外一按钮,可以获取到刚才保存进SDCard中的图片,将其加载的页面中的ImageView控件中。
2、示例代码: 、示例代码:
  1. public class MainActivity extends Activity {
  2. private ImageView imageView_main_img;
  3. private String urlString = "http://t2.baidu.com/it/u=2,1891512358&fm=19&gp=0.jpg";
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. imageView_main_img = (ImageView) findViewById(R.id.imageView_main_img);
  9. }
  10. public void clickButton(View view) {
  11. switch (view.getId()) {
  12. case R.id.button_main_save:
  13. new MyTask(this).execute(urlString);
  14. break;
  15. case R.id.button_main_show:
  16. String filepath = SDCardHelper.getSDCardPath() + File.separator + "mydir" + File.separator + "firstimg.jpg";
  17. byte[] data = SDCardHelper.loadFileFromSDCard(filepath);
  18. if (data != null) { Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
  19. imageView_main_img.setImageBitmap(bm);
  20. } else {
  21. Toast.makeText(this, "没有该图片!", Toast.LENGTH_LONG).show();
  22. }
  23. break;
  24. default:
  25. break;
  26. }
  27. }
  28. class MyTask extends AsyncTask<String, Void, byte[]> {
  29. private Context context;
  30. private ProgressDialog pDialog;
  31. public MyTask(Context context) {
  32. this.context = context;
  33. pDialog = new ProgressDialog(context);
  34. pDialog.setIcon(R.drawable.ic_launcher);
  35. pDialog.setMessage("图片加载中..."); }
  36. @Override
  37. protected void onPreExecute() {
  38. super.onPreExecute();
  39. pDialog.show();
  40. }
  41. @Override
  42. protected byte[] doInBackground(String... params) {
  43. BufferedInputStream bis = null;
  44. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  45. try {
  46. URL url = new URL(params[0]);
  47. HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
  48. httpConn.setDoInput(true);
  49. httpConn.connect();
  50. if (httpConn.getResponseCode() == 200) {
  51. bis = new BufferedInputStream(httpConn.getInputStream());
  52. byte[] buffer = new byte[1024 * 8];
  53. int c = 0;
  54. while ((c = bis.read(buffer)) != -1) {
  55. baos.write(buffer, 0, c);
  56. baos.flush();
  57. }
  58. return baos.toByteArray();
  59. }
  60. } catch (Exception e) {
  61. e.printStackTrace();
  62. } return null;
  63. }
  64. @Override
  65. protected void onPostExecute(byte[] result) {
  66. super.onPostExecute(result);
  67. if (result == null) {
  68. Toast.makeText(context, "图片加载失败!", Toast.LENGTH_LONG).show();
  69. } else {
  70. // 将字节数组转成Bitmap,然后将bitmap加载的imageview控件中
  71. // Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0,
  72. // result.length);
  73. // imageView_main_img.setImageBitmap(bitmap);
  74. if (SDCardHelper.saveFileToSDCard(result, "mydir", "firstimg.jpg")) {
  75. Toast.makeText(context, "图片保存OK!", Toast.LENGTH_LONG).show();
  76. } else {
  77. Toast.makeText(context, "图片保存失败!", Toast.LENGTH_LONG).show();
  78. }
  79. }
  80. pDialog.dismiss();
  81. }
  82. }
  83. @Override
  84. public boolean onCreateOptionsMenu(Menu menu) {
  85. getMenuInflater().inflate(R.menu.main, menu);
  86. return true;
  87. }
  88. }
  89. }
  90. }
  91. }




(五)、案例:SDCard文件浏览器

1、效果如图:

2、原理:利用File对象的listFile()方法获得File[]数组。将数组产生的信息填充在listview中。
核心代码中的重要方法:
  1. listFiles()
  2. isFile()
  3. isDirectory()
  4. getAbsolutePath()
  5. getParentFile()

3、核心示例代码:
public class MainActivity extends Activity {   private TextView textView_main_currentpath;   private ListView listView_main_fileList;    
  private File currentFile = null;   private File[] arrCurrentFiles = null;    
  @Override   
protected void onCreate(Bundle savedInstanceState) 
{   super.onCreate(savedInstanceState);   setContentView(R.layout.activity_main);      
      textView_main_currentpath = (TextView) findViewById(R.id.text_main_currentpath);  
      listView_main_fileList = (ListView) findViewById(R.id.listView_main_filelist);     
    if (SDCardHelper.isSDCardMounted()) { 
         currentFile = new File(SDCardHelper.getSDCardPath());   
                 fillListView(currentFile);   } else {   
                       Toast.makeText(MainActivity.this, "SDCARD不存在!", Toast.LENGTH_LONG)   .show();  
 }      listView_main_fileList   .setOnItemClickListener(new OnItemClickListener() {      
    @Override  
     public void onItemClick(AdapterView<?> parent, View view,   int position, long id) {   
                      if (arrCurrentFiles[position].isDirectory()) {   
                              File[] arrSubFiles = arrCurrentFiles[position] .listFiles(); 
           if (arrSubFiles.length == 0) {   Toast.makeText(MainActivity.this, "您点击的是空目录!",   2000).show();   
                    } else {   fillListView(arrCurrentFiles[position]);   
             }      } else {   Toast.makeText(MainActivity.this, "您点击的不是目录!",   
          Toast.LENGTH_LONG).show();   }   }   });      }      public void clickButton(View view) {   switch (view.getId()) {   case R.id.imageView_main_back:   if (!currentFile.getAbsolutePath().equals(   SDCardHelper.getSDCardPath())) {   fillListView(currentFile.getParentFile());   }   break;   default:   break;   }   }      public void fillListView(File file) {   currentFile = file;   arrCurrentFiles = currentFile.listFiles();      List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();   for (int i = 0; i < arrCurrentFiles.length; i++) {   Map<String, Object> map = new HashMap<String, Object>();   if (arrCurrentFiles[i].isDirectory()) {   map.put("imgId", R.drawable.folder);   } else {   map.put("imgId", R.drawable.file);   }   map.put("filename", arrCurrentFiles[i].getName());   list.add(map);   }      SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, list,   R.layout.item_listview_main,   new String[] { "imgId", "filename" }, new int[] {   R.id.imageView_item_listview_type,   R.id.text_item_listview_filename });   listView_main_fileList.setAdapter(adapter);   textView_main_currentpath.setText(currentFile.getAbsolutePath());   }   } 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号