編輯:關於Android編程
離線緩存就是在網絡暢通的情況下將從服務器收到的數據保存到本地,當網絡斷開之後直接讀取本地文件中的數據。
將網絡數據保存到本地:
你可以自己寫一個保存數據成本地文件的方法,保存在android系統的任意目錄(當然是有權限的才行),但是在這種情況下使用Context的openFileOutput方法最簡便也最符合我們的場景,下面的saveObject方法演示了如何用openFileOutput將數據保存在本地的一個文件中:
saveObject
public static boolean saveObject(Serializable ser, String file) { FileOutputStream fos = null; ObjectOutputStream oos = null; try { fos = AppContext.getInstance().openFileOutput(file, AppContext.getInstance().MODE_PRIVATE); oos = new ObjectOutputStream(fos); oos.writeObject(ser); oos.flush(); return true; } catch (Exception e) { e.printStackTrace(); return false; } finally { try { oos.close(); } catch (Exception e) { } try { fos.close(); } catch (Exception e) { } } }
openFileOutput可以直接獲得一個和應用關聯的文件路徑(在/data/data/writeObject
)到得到的文件中,你可以看到上面的實現過程有兩個關鍵方法:openFileOutput、writeObject
以及調用它們的兩個關鍵對象Context和ObjectOutputStream
。關於序列化可以參看這篇文章:Java對象的序列化和反序列化實踐
這是將一個序列化的對象保存在本地,跟我們的離線緩存保存網絡數據有什麼關系呢?
有關系,因為網上獲取的數據大多可以轉換成String類型的字符串,現在服務端返回的數據一般是json格式的字符串。而String類型的字符串其實就是可序列化的對象。下面是一個服務器返回json數據的例子(其實就是jcodecraeer網站的一個移動客戶端升級接口):
{url:http://jcodecraeer.com/uploads/soft/android/CodeBox.apk,versionCode:7,updateMessage:增加離線緩存,分類篩選功能修正了版本兼容性問題 }
用上面的saveObject方法我們可以將數據保存在本地,為了能夠取出這個文件我們必須想好如何為這個保存的文件命名,如果是單純的一篇文章的數據,我們可以直接將文件名命名為這篇文章的id,因為id是唯一的,為了盡可能的不和其他數據發生沖突,你還可以在這個id之前加一個前綴,比如這篇文章是java欄目下的我們可以這樣 arc_java_id。如果是文章列表我們可以這樣命名:文章類別_分頁頁碼,總之命名的原則是能和其他離線數據區別,有唯一性。為什麼不用url作為文件名呢?url肯定是唯一的,但是url不一定符合文件的命名規范。
下面來講解如何讀取本地緩存的數據
讀取緩存的時候我們只需要知道文件名就可以了,下面的readObject方法實現了根據文件名讀取緩存數據。其實很多東西是和上面保存數據對應的。
readObject
/** * 讀取對象 * * @param file * @return * @throws IOException */ public static Serializable readObject(String file) { FileInputStream fis = null; ObjectInputStream ois = null; try { fis = AppContext.getInstance().openFileInput(file); ois = new ObjectInputStream(fis); return (Serializable) ois.readObject(); } catch (FileNotFoundException e) { } catch (Exception e) { e.printStackTrace(); } finally { try { ois.close(); } catch (Exception e) { } try { fis.close(); } catch (Exception e) { } } return null; }
下面的代碼演示了如何用上面的知識存儲和讀取網絡數據
String key = codelist_ + mCategory.getValue() + _ + + page ; String result = ; //cache if (HttpUtil.isNetworkConnected()) { result = HttpUtil.http_get(AppContext.getInstance(), url ); HttpUtil.saveObject(result, key); result = (String) HttpUtil.readObject(key); } else { result = (String) HttpUtil.readObject(key); if (result == null) result = erro; }
當網絡暢通時,從服務器獲取數據( HttpUtil.http_get(AppContext.getInstance(), url )
),同時將數據保存到本地(HttpUtil.saveObject
),而當網絡不可用時,直接從本地讀取緩存的數據,不跟服務器發生交互。
其中HttpUtil
是跟網絡相關的工具類,這裡涉及到它的三個方法:
isNetworkConnected()判斷網絡是否可用 saveObject上面已經給出了實現 readObject上面已經給出了實現 http_get讀取指定url的服務器數據
而
AppContext.getInstance()
是我自己寫的,是為了方便在HttpUtil
的靜態方法中獲得Context對象。
這裡的key就是文件名。
額外的需求
有時候我們還有這樣的需求,當用戶在指定間隔時間內讀取同一數據源時,從本地獲取,超過這個時間間隔從網絡獲取,這樣做的目的是節省用戶的流量,同時也避免了每次從網絡獲取數據造成的界面延遲。
下面實現了如何根據時間間隔判斷是否需要刷新服務器數據,true表示不需要,false表示需要(很別扭是吧,這跟isCacheDataFailure
這個命名有關系):
public static boolean isCacheDataFailure(String cachefile) { boolean failure = false; File data = AppContext.getInstance().getFileStreamPath(cachefile); if (data.exists() && (System.currentTimeMillis() - data.lastModified()) > CACHE_TIME) failure = true; else if (!data.exists()) failure = true; return failure; }
將當前時間和文件的修改時間做比較 ,CACHE_TIME是一個固定值(毫秒),你可以替換成任意int類型。
將這個判斷條件加入,然後上面的代碼改成:
String key = codelist_ + mCategory.getValue() + _ + + page ; String result = ; //cache if (HttpUtil.isNetworkConnected() && HttpUtil.isCacheDataFailure(key)) { result = HttpUtil.http_get(AppContext.getInstance(), url ); HttpUtil.saveObject(result, key); result = (String) HttpUtil.readObject(key); } else { result = (String) HttpUtil.readObject(key); if (result == null) result = erro; }
完善
上面的步驟對於一般應用來說已經夠用了,但是在要求比較高的情況下,我們還得考慮隨著時間的流逝,緩存數據會越來越多,因此我們需要增加刪除過期緩存的功能,原理就是設置一個閥值,在保存緩存的時候,判斷當前緩存的總量是否大於閥值,如果是則刪除時間較早的緩存。
這個實現起來有點復雜,可以考慮更簡單的方案,定期檢查(或者用戶每打開一次程序)緩存總量,當大於閥值,提示用戶主動刪除。具體實現就不多說了。
注:openFileOutput()方法的第一參數用於指定文件名稱,不能包含路徑分隔符“/” ,如果文件不存在,Android 會自動創建它。創建的文件保存在/data/data/
openFileOutput()方法的第二參數用於指定操作模式,有四種模式,分別為: Context.MODE_PRIVATE = 0
Context.MODE_APPEND = 32768
Context.MODE_WORLD_READABLE = 1
Context.MODE_WORLD_WRITEABLE = 2
Context.MODE_PRIVATE:為默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容,如果想把新寫入的內容追加到原文件中。可以使用Context.MODE_APPEND
Context.MODE_APPEND:模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用來控制其他應用是否有權限讀寫該文件。
MODE_WORLD_READABLE:表示當前文件可以被其他應用讀取;MODE_WORLD_WRITEABLE:表示當前文件可以被其他應用寫入。
如果希望文件被其他應用讀和寫,可以傳入:
openFileOutput(“itcast.txt”, Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE)
前言:好幾天電腦打不開CSDN博客,也不知道怎麼回事,今天下班回來突然能打開了,遂將周末實現的一個效果貼上。實現功能:獲取手機應用圖標,名稱,時間(安裝時間/更新時間),
360奇酷手機出自酷派和360合資公司,奇酷手機以及酷派手機都屬於安卓系統,那麼奇酷手機、酷派手機怎麼刷機呢?手機有毛病可以嘗試恢復手機出廠設置,操作方法如
主要實現兩個步驟:1、實現打開和關閉閃光燈;而實現操作閃光燈主要通過Camera類Camera camera = Camera.open(); Parameters mP
最近幾年,很多跨平台游戲框架已經出現。這些框架來填補空白,由於不斷增長的興趣和多樣性的移動游戲平台越來越大。今天是采取比以往任何時候都更容易游戲引擎和開發你的第一個游戲。