編輯:開發入門
清單 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.openFileInput
、openFileOutput
和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 應用程序時利用所有這些類型的存儲器。
在仿真器上運行應用程序為部署和運行應用程序,您需要定義一個運行配置。在 Eclipse 內選擇 Open > Run > Dialog
Android 應用程序一個最常見的任務就是檢索數據或通過網絡將數據發送到遠程服務器。這一操作的結果通常是一些您想要展示給用戶的新數據。這意味著您需要修改用戶界面。大多
簡介: 這是由兩部分組成的 Android 動畫框架詳解的第二部分實例篇。在閱讀本篇之前,建議您首先閱讀本系列的第一部分 Android 動畫框架詳解之原理篇
現在采用安卓系統的手機和平板電腦那是越來越多了,總是聽別人說安卓系統如何如何好,相信大家也想體驗一下安卓系統的獨特魅力吧!不過對於大多數手頭並不寬裕的朋友來說,僅僅為嘗