Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android游戲 >> Android游戲開發 >> Android游戲開發12:使用SharedPreference與FileInputStream/FileOutputStream保存數據

Android游戲開發12:使用SharedPreference與FileInputStream/FileOutputStream保存數據

編輯:Android游戲開發

       Android游戲開發中常用的保存數據的方式有四種,分別是SharedPreference、文件存儲、SQLite和ContentProvider。下面先作簡單的介紹。

       1、SharedPreference

       此保存方式試用於簡單數據的保存,文如其名屬於配置性質的保存,不適合數據比較大的保存方式。

       2、文件存儲(FIleInputStream/FileOutputStream)

       此保存方式比較適合游戲的保存和使用,可以保存較大的數據,因為相對於SQLite來說更容易讓童鞋們接受,此方式不僅能把數據存儲在系統中也能將數據保存到SDcard中。

       3、SQLite

       此保存方式比較適合游戲的保存和使用,可以保存較大的數據,並且可以將自己的數據存儲到文件系統或者數據庫當中,也可以將自己的數據存儲到SQLite數據庫當中,也能將數據保存到SDcard中。

       4、ContentProvider(不推薦用於戲保存)

       此保存方式不推薦用於游戲保存,因為此方式不僅能存儲較大數據,還支持多個程序之間就的數據進行交換!但是由於游戲中基本就不可能去訪問外部應用的數據,所以對於此方式我不予講解, 有興趣的可以自己找資料 學習。

       以上對幾種常用的保存方式進行了概述,下面分別講解每種方式的優缺點、如何實現和需要注意的問題。

       1、保存方式之SharedPreference

       優點: 簡單、方便、適合簡單數據的快速保存。

       缺點:

       1)存數的文件只能在同一包內使用,不能在不同包之間使用!

       2)默認將數據存放在系統路徑下 /data/data/com.himi/ ,沒有找到放SD卡上的方法。

       總結:其實本保存方式如同它的名字一樣是個配置保存,雖然方便,但只適合存儲比較簡單的數據!

       main.xml  :

XML/HTML代碼
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <TextView android:layout_width="fill_parent"  
  6.         android:layout_height="wrap_content" android:text="保存數據練習!"  
  7.         android:textSize="20sp" android:textColor="#ff0000" android:id="@+id/tv_title" />  
  8.     <TextView android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content" android:text="請輸入帳號" />  
  10.     <EditText android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content" android:id="@+id/editText_Login"  
  12.         android:text=""></EditText>  
  13.     <TextView android:layout_width="fill_parent"  
  14.         android:layout_height="wrap_content" android:text="請輸入密碼" />  
  15.     <EditText android:layout_width="fill_parent"  
  16.         android:layout_height="wrap_content" android:id="@+id/editText_Password"  
  17.         android:text=""></EditText>  
  18.     <Button android:id="@+id/button_save" android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content" android:text="保存"></Button>  
  20.     <Button android:id="@+id/button_load" android:layout_width="wrap_content"  
  21.         android:layout_height="wrap_content" android:text="取出數據"  
  22.         android:visibility="invisible"></Button>  
  23. </LinearLayout>  

       先把xml文件放上來的原因是因為我在此篇中介紹的 SharedPreference 和 文件存儲 (FIleInputStream/FileOutputStream),都共用此xml,很簡單,兩個textview 兩個 editview 以及兩個button,這裡就不多說了。

       下面是SharedPreference 的代碼實現和詳細講解:

Java代碼
  1. /**  
  2.  * @author Himi  
  3.  * @保存方式:SharedPreference  
  4.  * @注意:SharedPreference 可以跨程序包使用,多謝二樓童鞋提醒!  
  5.  * @操作模式: Context.MODE_PRIVATE:新內容覆蓋原內容  
  6.  *            Context.MODE_APPEND:新內容追加到原內容後  
  7.  *            Context.MODE_WORLD_READABLE:允許其他應用程序讀取  
  8.  *            Context.MODE_WORLD_WRITEABLE:允許其他應用程序寫入,會覆蓋原數據。  
  9.  */  
  10. public class MainActivity extends Activity implements OnClickListener {   
  11.     private EditText et_login, et_password;   
  12.     private Button btn_save;   
  13.     private TextView tv_title;   
  14.     private SharedPreferences sp;   
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {   
  17.         super.onCreate(savedInstanceState);   
  18.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,   
  19.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);   
  20.         this.requestWindowFeature(Window.FEATURE_NO_TITLE);   
  21.         setContentView(R.layout.main);   
  22.         btn_save = (Button) findViewById(R.id.button_save);   
  23.         btn_save.setOnClickListener(this);   
  24.         et_login = (EditText) findViewById(R.id.editText_Login);   
  25.         et_password = (EditText) findViewById(R.id.editText_Password);   
  26.         tv_title = (TextView) findViewById(R.id.tv_title);   
  27.         // 這裡我們先調用 getSharedPreferences()來實例化一個SharedPreferences,   
  28.         // 第二個參數是指:操作模式(上面對各種操作模式已有解釋)   
  29.         sp = getSharedPreferences("Setting_himi", MODE_PRIVATE);   
  30.         /*  
  31.          * 下面代碼是我們要在程序剛啟動的時候我們來讀取之前的數據,  
  32.          * 當然我們還沒有保存任何數據所以肯定找不到!!  
  33.          * 如果找不到也沒關系會默認返回一個參數值,看下面的方法含義便知!  
  34.          */  
  35.         sp.getString("login", "");   
  36.         // getString()類似哈希表,一個key 一個volue ,   
  37.         // 這個方法如果找不到對應的第一個參數(key),那麼將以第二個參數作為此key的返回值   
  38.         et_login.setText(sp.getString("login", ""));   
  39.         et_password.setText(sp.getString("password", ""));   
  40.     }   
  41.     @Override  
  42.     public void onClick(View v) {   
  43.         if (v == btn_save) {   
  44.             if (et_login.getText().toString().equals(""))   
  45.                 tv_title.setText("請輸入帳號!");   
  46.             else if (et_password.getText().toString().equals(""))   
  47.                 tv_title.setText("請輸入密碼!");   
  48.             else {   
  49.                 sp.edit()   
  50.                   .putString("login", et_login.getText().toString())   
  51.                   .putString("password", et_password.getText().toString())   
  52.                   .commit();   
  53.                 // 從sp.edit()開始進入編輯狀態,直到commit()提交!   
  54.                 tv_title.setText("保存成功!可重新打開此程序,測試是否已經保存數據!" +   
  55.                     "/n(或者在'File Explorer'窗口下-data-data-com.himi路徑下" +   
  56.                     "是否存在" +"了'Setting_himi.xml')");   
  57.             }   
  58.         }   
  59.     }   
  60. }  

       代碼中的注釋的很清楚了,比較簡單,不多說了。

       2、保存方式之:文件存儲 OutputStream/InputStream

       優點:

       1)適合游戲存儲,能存儲較大數據;

       2)不僅能存儲到系統中,也能存儲到SD卡中!

       總結:如果童鞋們對SQL不太熟習的話那麼選擇此種方式最為合適的啦。

Java代碼
  1. /**  
  2.  * @author Himi  
  3.  * @保存方式:Stream 數據流方式  
  4.  * @注意1:默認情況下,使用openFileOutput 方法創建的文件只能被其調用的應用使用,  
  5.  *         其他應用無法讀取這個文件,如果需要在不同的應用中共享數據;  
  6.  *  
  7.  * @注意2:因為android  os內部閃存有限,所以適合保存較少的數據,當然我們也有解決的方法,  
  8.  *         就是把數據保存在SD開中,這樣就可以了,後面我也會向大家講解   !  
  9.  *  
  10.  * @提醒1 調用FileOutputStream 時指定的文件不存在,Android 會自動創建它。  
  11.  *        另外,在默認情況下,寫入的時候會覆蓋原 文件內容,如果想把新寫入的內  
  12.  *        容附加到原文件內容後,則可以指定其mode為Context.MODE_APPEND。  
  13.  *  
  14.  * @提醒2 啟動程序就初始化的時候一定要注意處理!代碼中有注釋!一定要仔細看!  
  15.  *  
  16.  * @提醒3 這裡我給大家講兩種方式,一種是原生態file流來寫入/讀入,  
  17.  *        另外一種是用Data流包裝file流進行寫入/讀入 其實用data流來包裝進行操作;  
  18.  *        原因是:包裝後支持了更多的寫入/讀入操作,比如:file流寫入不支持  
  19.  *        writeUTF(String str); 但是用Data包裝後就會支持。  
  20.  *  
  21.  * @操作模式: Context.MODE_PRIVATE:新內容覆蓋原內容  
  22.  *            Context.MODE_APPEND:新內容追加到原內容後  
  23.  *            Context.MODE_WORLD_READABLE:允許其他應用程序讀取  
  24.  *            Context.MODE_WORLD_WRITEABLE:允許其他應用程序寫入,會覆蓋原數據。  
  25.  */  
  26. public class MainActivity extends Activity implements OnClickListener {   
  27.     private EditText et_login, et_password;   
  28.     private Button btn_save;   
  29.     private TextView tv_title;   
  30.     private FileOutputStream fos;   
  31.     private FileInputStream fis;   
  32.     private DataOutputStream dos;   
  33.     private DataInputStream dis;   
  34.     @Override  
  35.     public void onCreate(Bundle savedInstanceState) {   
  36.         String temp = null;   
  37.         super.onCreate(savedInstanceState);   
  38.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,   
  39.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);   
  40.         this.requestWindowFeature(Window.FEATURE_NO_TITLE);   
  41.         setContentView(R.layout.main);   
  42.         btn_save = (Button) findViewById(R.id.button_save);   
  43.         btn_save.setOnClickListener(this);   
  44.         et_login = (EditText) findViewById(R.id.editText_Login);   
  45.         et_password = (EditText) findViewById(R.id.editText_Password);   
  46.         tv_title = (TextView) findViewById(R.id.tv_title);   
  47.         try {   
  48.             // openFileInput 不像 sharedPreference 中   
  49.             // getSharedPreferences的方法那樣找不到會返回默認值,   
  50.             // 這裡找不到數據文件就會報異常,所以finally裡關閉流尤為重要!!!   
  51.             if (this.openFileInput("save.himi") != null) {   
  52.                 // --------------單純用file來讀入的方式-----------------   
  53.                 // fis = this.openFileInput("save.himi");   
  54.                 // ByteArrayOutputStream byteArray = new   
  55.                 // ByteArrayOutputStream();   
  56.                 // byte[] buffer = new byte[1024];   
  57.                 // int len = 0;   
  58.                 // while ((len = fis.read(buffer)) > 0) {   
  59.                 // byteArray.write(buffer, 0, len);   
  60.                 // }   
  61.                 // temp = byteArray.toString();   
  62.                 // -------------- 用data流包裝後的讀入的方式------------   
  63.                 fis = this.openFileInput("save.himi");//備注1   
  64.                 dis = new DataInputStream(fis);   
  65.                 et_login.setText(dis.readUTF());   
  66.                 et_password.setText(dis.readUTF());   
  67.                 // 這裡也是在剛啟動程序的時候去讀入存儲的數據   
  68.                 // 讀的時候要注意順序; 例如我們寫入數據的時候   
  69.                 //先寫的字符串類型,我們也要先讀取字符串類型,一一對應!   
  70.             }   
  71.         } catch (FileNotFoundException e) {   
  72.             // TODO Auto-generated catch block   
  73.             e.printStackTrace();   
  74.         } catch (IOException e) {   
  75.             // TODO Auto-generated catch block   
  76.             e.printStackTrace();   
  77.         } finally {   
  78.             // 在finally中關閉流!因為如果找不到數據就會異常我們也能對其進行關閉操作 ;   
  79.             try {   
  80.                 if (this.openFileInput("save.himi") != null) {   
  81.                     // 這裡也要判斷,因為找不到的情況下,兩種流也不會實例化。   
  82.                     // 既然沒有實例化,還去調用close關閉它,肯定"空指針"異常!!!   
  83.                     fis.close();   
  84.                 }   
  85.             } catch (FileNotFoundException e) {   
  86.                 // TODO Auto-generated catch block   
  87.                 e.printStackTrace();   
  88.             } catch (IOException e) {   
  89.                 // TODO Auto-generated catch block   
  90.                 e.printStackTrace();   
  91.             }   
  92.         }   
  93.     }   
  94.     @Override  
  95.     public void onClick(View v) {   
  96.         if (Environment.getExternalStorageState() != null) {   
  97.             // 這個方法在試探終端是否有sdcard!   
  98.             Log.v("Himi", "有SD卡");   
  99.         }   
  100.         if (v == btn_save) {   
  101.             if (et_login.getText().toString().equals(""))   
  102.                 tv_title.setText("請輸入帳號!");   
  103.             else if (et_password.getText().toString().equals(""))   
  104.                 tv_title.setText("請輸入密碼!");   
  105.             else {   
  106.                 try {   
  107.                     // ------單純用file來寫入的方式--------------   
  108.                     //fos = new FileOutputStream(f);   
  109.                     // fos.write(et_login.getText().toString().getBytes());   
  110.                     // fos.write(et_password.getText().toString().getBytes());   
  111.                     // ------data包裝後來寫入的方式--------------   
  112.                     fos = this.openFileOutput("save.himi", MODE_PRIVATE);//備注2   
  113.                     dos = new DataOutputStream(fos);   
  114.                     dos.writeUTF(et_login.getText().toString());   
  115.                     dos.writeUTF(et_password.getText().toString());   
  116.                     tv_title.setText("保存成功!可重新打開此程序,測試是" +   
  117.                             "否已經保存數據!/n(或者在'File Explorer'" +   
  118.                             "窗口下-data-data-com.himi-files路徑下" +   
  119.                             "是否存在了'save.himi')");   
  120.                 } catch (FileNotFoundException e) {   
  121.                     // TODO Auto-generated catch block   
  122.                     e.printStackTrace();   
  123.                 } catch (IOException e) {   
  124.                     // TODO Auto-generated catch block   
  125.                     e.printStackTrace();   
  126.                 } finally {   
  127.                     // 在finally中關閉流 這樣即使try中有異常我們也能對其進行關閉操作 ;   
  128.                     try {   
  129.                         dos.close();   
  130.                         fos.close();   
  131.                     } catch (IOException e) {   
  132.                         // TODO Auto-generated catch block   
  133.                         e.printStackTrace();   
  134.                     }   
  135.                 }   
  136.             }   
  137.         }   
  138.     }   
  139. }  

       以上代碼中實現了兩種流形式來完成寫入和讀入,這裡我們為什麼要使用Data流來包裝,其實不光是獲得更多的操作方式,最主要的是方便快捷,你比如用file來讀入的時候,明顯的復雜了一些不說,它還一次性把所有數據都取出來了,不便於對數據的處理!

       強調的有幾點:

       1、在一開始對數據的訪問再次提醒童鞋們,這個跟sharedPreference的獲取方式不一樣,sharedPreference 的獲取方式可以得到一個默認的值,但是你用咱們獲取的是個文件 而且直接就去open這個文件,一旦不存在必定異常,所以這一塊的異常處理,以及finally的處理一定要處理得當。

       2、其實在一開始用data包裝的時候發現寫入的字符串在讀入的時候發現字符亂碼了,查了api才發現,api規定當寫入字符串的時候必須寫入UTF-8格式的編碼,但是後來不知道怎麼了就沒事了。所以這裡如果童鞋們遇到此問題,我給出大家一個解決方法,就是在寫入的時候我們不要去DataOutputStream 來包裝而是用,OutputStreamWriter ,因為在構造的可以設定編碼!

       OutputStreamWriter osw = new OutputStreamWriter(fis,”UTF-8″);

       String  content = EncodingUtils.getString(buffer, ”UTF-8″);  這個也能把字符數組轉碼制!

       這樣寫入的就肯定是UTF-8編碼的字符啦。

       下面介紹如何把我們的數據通過 OutputStream/InputStream 存入SD卡中!

       其實將我們的數據放入SD卡中,無疑就需要對代碼進行兩處的修改:

       注意:一定要有SD卡!對於如何創建SD卡在前面文章中已經說了兩種方式,不會的童鞋可以去看下。

       第一:檢查是否裝有SD卡;

       第二:修改讀入的地方(備注1)。

       fis = this.openFileInput(“save.himi”); //這裡沒有路徑,路徑是默認的 data-data-com.himi-files下

       替換成我們的SD卡的路徑就可以了:

       File path = new File(“/sdcard/himi/save.himi”);//這裡新建一個File目錄路徑

       fis = new FileInputStream(path);傳入路徑

       第三:修改寫入的地方(備注2)。

       fos = this.openFileOutput(“save.himi”, MODE_PRIVATE);這裡也是默認路徑,需要對其修改。

       注意:這裡修改了,那麼在finally中的判定大家也要對應的適當修改;

       注意:如果是系統路徑,當沒有此文件的時候,android 會默認創建一個!但是我們放入SD卡的時候要自己創建目錄路徑和文件!

Java代碼
  1. if (Environment.getExternalStorageState() != null) {// 這個方法在試探終端是否有sdcard!   
  2.        Log.v("Himi", "有SD卡");   
  3.        File path = new File("/sdcard/himi");// 創建目錄   
  4.        File f = new File("/sdcard/himi/save.himi");// 創建文件   
  5.        if (!path.exists()) {// 目錄不存在返回false   
  6.            path.mkdirs();// 創建一個目錄   
  7.        }   
  8.        if (!f.exists()) {// 文件不存在返回false   
  9.            f.createNewFile();// 創建一個文件   
  10.        }   
  11.        fos = new FileOutputStream(f);// 將數據存入sd卡中   
  12. }  

       第四:因為我們要在SD卡中進行寫入的操作,所以要在配置文件中聲明權限!

XML/HTML代碼
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.himi"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  7.         <activity android:name=".MainActivity"  
  8.                   android:label="@string/app_name">  
  9.             <intent-filter>  
  10.                 <action android:name="android.intent.action.MAIN" />  
  11.                 <category android:name="android.intent.category.LAUNCHER" />  
  12.             </intent-filter>  
  13.         </activity>  
  14.     </application>  
  15.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
  16.     <uses-sdk android:minSdkVersion="4" />  
  17. </manifest>  

       這一句就是啦~

       <uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>

       為了讓大家看到所放的位置,所以把整個xml放出來供參考。

       那麼當創建路徑和文件的時候,我們對其檢查SD卡中是否已經存在exists()方法 ,如果已經存在就不去創建,這樣避免下次再次寫入數據的時候又新建了文件和路徑。

       其實我們在可以在啟動程序的時候判斷如果沒有此文件,我們可以直接緊接著創建一個文件,這些都屬於優化上的了,我主要是讓大家引入,學會,那麼其他的簡化啦,優化啦,其他方式去實現啦都留給各位同學自己了。

       本文效果圖:

 Android游戲開發12:使用SharedPreference與FIleInputStream/FileOutputStream保存數據

       OK、今天就先介紹到這裡,後面會單獨剖析SQLite如何存入數據,以及對數據操作的! 希望大家繼續關注!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved