Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 開發入門 >> Android 開發教程之本地數據存儲 API(二)

Android 開發教程之本地數據存儲 API(二)

編輯:開發入門

清單 13. 刪除數據庫表

				
    /**
     * Wipe out the DB
     */
    public void clearAll() {
        db.delete(TABLE_NAME, null, null);
    }

 

提供了兩個 SELECT ALL 方法:cursorSelectAll() 和listSelectAll(),前者返回一個游標,後者返回一個 FrIEnd 對象ArrayList。這些方法在從數據庫加載信息時由 MainActivity 調用(參見 清單 14)。


清單 14. 運行返回 ArrayList 的 Select All

				
    /**
     * Select All returns a cursor
     * @return the cursor for the DB selection
     */
    public Cursor cursorSelectAll() {
        Cursor cursor = this.db.query(
                TABLE_NAME, // Table Name
                new String[] { "fid", "name" }, // Columns to return
                null,       // SQL WHERE
                null,       // Selection Args
                null,       // SQL GROUP BY 
                null,       // SQL HAVING
                "name");    // SQL ORDER BY
        return cursor;
    }

 

listSelectAll() 方法返回 ArrayList 容器中選定的行,該容器由MainActivity 用來將它綁定到 MainScreen ListVIEw(參見 清單 15)。


清單 15. 運行返回游標的 Select All

				
    /**
     * Select All that returns an ArrayList
     * @return the ArrayList for the DB selection
     */
    public ArrayList<Friend> listSelectAll() {
        ArrayList<Friend> list = new ArrayList<Friend>();
        Cursor cursor = this.db.query(TABLE_NAME, new String[] { "fid", "name" }, 
null, null, null, null, "name");
        if (cursor.moveToFirst()) {
            do {
                Friend f = new FrIEnd();
                f.id = cursor.getString(0);
                f.name = cursor.getString(1);
                list.add(f);
            } while (cursor.moveToNext());
        }
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
        return list;
    }

 

如果檢測到數據庫版本更改,就會調用 onUpgrade() 方法(參見 清單 16)。


清單 16. 檢測數據庫版本是否更改

				
    /**
     * Invoked if a DB upgrade (version change) has been detected
     */
    @Override
    /**
     * Invoked if a DB upgrade (version change) has been detected
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, 
       int oldVersion, int newVersion) {
        // Here add any steps needed due to version upgrade
        // for example, data format conversions, old tables 
        // no longer needed, etc
    }
}

 

整個 MainActivity 中,當您將信息導出到數據庫、從數據庫加載信息以及清理數據庫時,都會使用 DBHelper。第一件事是在創建MainActivity 時實例化 DBHelper。在 onCreate() 時執行的其他任務包括初始化不同的屏幕視圖(參見 清單 17)。


清單 17. MainActivity onCreate() 初始化數據庫

				
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    appContext = this;
    setContentView(R.layout.main);
    dbHelper = new DBHelper(this);
    listView = (ListView) findViewById(R.id.friendsview);
    friendsArrayAdapter = new FriendsArrayAdapter(
       this, R.layout.rowlayout, friends);
    listView.setAdapter(frIEndsArrayAdapter);
    :
    :
}

 

清單 18 展示了如何從資產加載好友列表以及如何將之解析並插入數據庫中。


清單 18. MainActivity 插入到數據庫中

				
String fname = prefsGetFilename();
if (fname != null && fname.length() > 0) {
    buffer = getAsset(fname);
    // Parse the JSON file
    String friendslist = new String(buffer);
    final JSONObject json = new JSONObject(frIEndslist);
    JSONArray d = json.getJSONArray("data");
    int l = d.length();
    for (int i2=0; i2<l; i2++) {
        JSONObject o = d.getJSONObject(i2);
        String n = o.getString("name");
        String id = o.getString("id");
        dbHelper.insert(id, n);
    }
    // Only the original owner thread can touch its views                           
    MainActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            frIEndsArrayAdapter.notifyDataSetChanged();
        }
    });         
}

 

清單 19 展示了如何執行 SELECT ALL 以及如何將數據綁定到主屏幕ListVIEw


清單 19. MainActivity Select All 和將數據綁定到ListVIEw

				
final ArrayList<Friend> dbFriends = dbHelper.listSelectAll();
if (dbFriends != null) {
    // Only the original owner thread can touch its views                           
    MainActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            friendsArrayAdapter = 
            new FriendsArrayAdapter(
                MainActivity.this, R.layout.rowlayout, dbFriends);
            listView.setAdapter(friendsArrayAdapter);
            frIEndsArrayAdapter.notifyDataSetChanged();
        }
    });
}                           

 

接下來,了解一下在示例應用程序中使用 Internal Storage API。


為私有數據使用設備的內部存儲器

有了數據存儲 API,您可以使用內部存儲器存儲數據。信息可以是私有的,您可以有選擇地讓其他應用程序對之具有讀或寫的訪問權限。本節介紹這個存儲私有數據的 API,它使用android.content.Context.openFileInputopenFileOutput 和getCacheDir() 來高速緩存數據,而不是永久地存儲。

清單 20 中的代碼片段展示了如何從內部私有存儲器讀取數據。使得存儲器為私有的方法是對 openFileOutput() 使用 MODE_PRIVATE


清單 20. 從本地私有存儲器讀取數據

				
/**
 * Writes content to internal storage making the content private to 
 * the application. The method can be easily changed to take the MODE 
 * as argument and let the caller dictate the visibility: 
 * MODE_PRIVATE, MODE_WORLD_WRITEABLE, MODE_WORLD_READABLE, etc.
 * 
 * @param filename - the name of the file to create
 * @param content - the content to write
 */
public void writeInternalStoragePrivate(
        String filename, byte[] content) {
    try {
        //MODE_PRIVATE creates/replaces a file and makes 
        //  it private to your application. Other modes:
        //    MODE_WORLD_WRITEABLE
        //    MODE_WORLD_READABLE
        //    MODE_APPEND
        FileOutputStream fos = 
           openFileOutput(filename, Context.MODE_PRIVATE);
        fos.write(content);
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

清單 21 中的代碼片段展示了如何從內部私有存儲器讀取數據;注意openFileInput() 的使用。


清單 21. 從內部私有存儲器讀取數據

				
/**
 * Reads a file from internal storage
 * @param filename the file to read from
 * @return the file content
 */
public byte[] readInternalStoragePrivate(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    try {
        FileInputStream fis = openFileInput(filename);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int nrb = fis.read(buffer, 0, len); // read up to len bytes
        while (nrb != -1) {
            baos.write(buffer, 0, nrb);
            nrb = fis.read(buffer, 0, len);
        }
        buffer = baos.toByteArray();
        fis.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return buffer;
}

 

清單 22 展示了如何從內部私有存儲器刪除數據。


清單 22. 從本地私有存儲器刪除數據

				
/**
 * Delete internal private file 
 * @param filename - the filename to delete
 */
public void deleteInternalStoragePrivate(String filename) {
    File file = getFileStreamPath(filename);
    if (file != null) {
        file.delete();
    }
}

 

現在可以來看為公共數據使用外部存儲器了。


為公共數據使用設備的外部存儲器

有了數據存儲 API,您可以使用外部存儲器存儲數據。信息可以是私有的,您可以有選擇地讓其他應用程序對之具有讀或寫的訪問權限。本節您將對此 API 進行編程,以便使用包括getExternalStorageState()getExternalFilesDir()getExternalStorageDirectory()和 getExternalStoragePublicDirectory() 在內的很多 API 來存儲公共數據。您為公共數據使用下面的路徑:/android/data/<package_name>/files/

在使用外部存儲器之前,必須看看它是否可用,是否可寫。下面兩個代碼片段展示了測試這些條件的幫助器方法。清單 23 測試外部存儲器是否可用。


清單 23. 測試外部存儲器是否可用

				
/**
 * Helper Method to Test if external Storage is Available
 */
public boolean isExternalStorageAvailable() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
        state = true;
    }
    return state;
}

 

清單 24 測試外部存儲器是否只可讀。


清單 24. 測試外部存儲器是否只可讀

				
/**
 * Helper Method to Test if external Storage is read only
 */
public boolean isExternalStorageReadOnly() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
        state = true;
    }
    return state;
}

 

清單 25 展示了如何寫到外部存儲器,以存儲公共數據。


清單 25. 寫到外部內存

				
/**
 * Write to external public directory
 * @param filename - the filename to write to
 * @param content - the content to write 
 */
public void writeToExternalStoragePublic(String filename, byte[] content) {

    // API Level 7 or lower, use getExternalStorageDirectory() 
    //  to open a File that represents the root of the external 
    // storage, but writing to root is not recommended, and instead 
    // application should write to application-specific directory, as shown below.

    String packageName = this.getPackageName();
    String path = "/android/data/" + packageName + "/files/";

    if (isExternalStorageAvailable() && 
       !isExternalStorageReadOnly()) {
        try {
            File file = new File(path, filename);
            file.mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(content);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

清單 26 展示了如何從外部存儲器讀取數據。


清單 26. 從外部內存讀取數據

				
/**
 * Reads a file from internal storage
 * @param filename - the filename to read from
 * @return the file contents
 */
public byte[] readExternallStoragePublic(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    String packageName = this.getPackageName();
    String path = "/android/data/" + packageName + "/files/";

    if (!isExternalStorageReadOnly()) {     
        try {
            File file = new File(path, filename);            
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int nrb = fis.read(buffer, 0, len); //read up to len bytes
            while (nrb != -1) {
                baos.write(buffer, 0, nrb);
                nrb = fis.read(buffer, 0, len);
            }
            buffer = baos.toByteArray();
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return buffer;
}

 

清單 27 中的代碼片段展示了如何從外部內存刪除文件。


清單 27. 從外部內存刪除文件

				
/**
 * Delete external public file 
 * @param filename - the filename to write to
 */
void deleteExternalStoragePublicFile(String filename) {
    String packageName = this.getPackageName();
    String path = "/android/data/" + packageName + "/files/"+filename;
    File file = new File(path, filename);
    if (file != null) {
        file.delete();
    }
}

 

處理外部存儲器需要特殊的權限 WRITE_EXTERNAL_STORAGE,它通過 androidManifest.XML 請求得到(參見 清單 28)。


清單 28. WRITE_EXTERNAL_STORAGE

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

 

外部存儲 API 通過根據文件類型(比如 Pictures、Ringtones)將文件存儲在預先確定的目錄中,允許您公共地存儲文件。本文沒有介紹這種方法,但是您應該熟悉它。此外,記住外部存儲器中的文件任何時候都可能消失。


相關的方法

如果您具有不需要長期永久保存的臨時文件,那麼可以將這些文件存儲在高速緩存中。高速緩存是一種特殊的內存,可以用於存儲中小型數據(少於兆字節),但是您一定要知道,取決於有多少內存可用,高速緩存的內容任何時候都可能被清除。

清單 29 展示了一個幫助器方法,它返回到內部內存中高速緩存的路徑。


清單 29. 檢索到內部內存高速緩存的路徑

				
/**
 * Helper method to retrIEve the absolute path to the application 
 * specific internal cache directory on the file system. These files 
 * will be ones that get deleted when the application is uninstalled or when 
 * the device runs low on storage. There is no guarantee when these 
 * files will be deleted.
 * 
 * Note: This uses a Level 8+ API.
 * 
 * @return the absolute path to the application specific cache 
 * directory
 */
public String getInternalCacheDirectory() {
    String cacheDirPath = null;
    File cacheDir = getCacheDir();
    if (cacheDir != null) {
        cacheDirPath = cacheDir.getPath();
    }
    return cacheDirPath;        
}

 

清單 30 展示了一個幫助器方法,它返回到外部內存中高速緩存的路徑。


清單 30. 檢索到外部內存高速緩存的路徑

				
/**
 * Helper method to retrIEve the absolute path to the application 
 * specific external cache directory on the file system. These files 
 * will be ones that get deleted when the application is uninstalled or when 
 * the device runs low on storage. There is no guarantee when these 
 * files will be deleted.
 * 
 * Note: This uses a Level 8+ API.
 * 
 * @return the absolute path to the application specific cache 
 * directory
 */
public String getExternalCacheDirectory() {
    String extCacheDirPath = null;
    File cacheDir = getExternalCacheDir();
    if (cacheDir != null) {
        extCacheDirPath = cacheDir.getPath();
    }
    return extCacheDirPath;     
}

 

通過使用示例應用程序,您現在應該很好地理解了如何為公共數據使用設備的外部存儲器。


結束語

本文介紹了幾個 Android 存儲 API,從首選項到使用 SQLite 和內部及外部內存。利用首選項 API,您可以讓自己的應用程序收集和存儲簡單的首選項信息。使用 SQLite API,您可以存儲更復雜的數據,利用內部和外部存儲器,您可以存儲對應用程序是私有的或者對其他應用程序公共可用的文件。跨多個會話持久存儲的已存儲數據讓您的應用程序甚至在與網絡斷開連接時仍然能夠工作。您現在應該掌握了在開發 android 應用程序時利用所有這些類型的存儲器。

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