日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

三級緩存的含義和如何實戰(zhàn)使用? | TeachCourse

 昵稱m59zD 2016-03-30

一.摘要

Android項目開發(fā)經(jīng)常需要使用到網(wǎng)絡(luò)訪問數(shù)據(jù),將獲取到的數(shù)據(jù)保存到本地,本地數(shù)據(jù)使用時寫入到內(nèi)存,再次訪問的時候從內(nèi)存獲取數(shù)據(jù),這就是平時說的三級緩存,三級緩存聽起來很“高大上”,其實集合了網(wǎng)絡(luò)訪問數(shù)據(jù)/本地訪問數(shù)據(jù)/緩存訪問數(shù)據(jù)三個級別,按理說不是什么困難的事情,前提是你對數(shù)據(jù)操作的的三種方式都熟悉。
three-cache-demo

二.網(wǎng)絡(luò)訪問數(shù)據(jù)

Android提供網(wǎng)絡(luò)訪問數(shù)據(jù)的類是:HttpURLConnection(最基礎(chǔ)的訪問方式),在實際開發(fā)中,我一直使用的第三方的開發(fā)框架:android-async-http-0.4.5.jar,它的特點是:1. UI線程中調(diào)用,異步執(zhí)行;2.實現(xiàn)接口AsyncHttpResponseHandler回調(diào)方法;3.涉及的類AsyncHttpClient/RequestParams/AsyncHttpResponseHandler,簡單的例子:

  1. public class BaseAPI {  
  2.       
  3.     public static String BASE_URL = 'http://122.76.77.16:8080';  
  4.     protected static AsyncHttpClient client;  
  5.   
  6.     static {  
  7.         client = new AsyncHttpClient();  
  8.     }  
  9.     /** 
  10.      * 設(shè)置http請求超時時間,默認為60s 
  11.      *  
  12.      * @param timeOut 
  13.      */  
  14.     protected static void setTimeOut(int timeOut) {  
  15.         client.setTimeout(timeOut);  
  16.     }  
  17.           
  18.     public static void getLoginState(String name,String psw,AsyncHttpResponseHandler responseHandler) {  
  19.         RequestParams params = new RequestParams();  
  20.                 params.put('name', name);  
  21.         params.put('psw', psw);  
  22.         client.post(BASE_URL, params, responseHandler);  
  23.     }  
  24. }  

更加詳細的使用說明,可以參考《Android開發(fā)之?dāng)?shù)據(jù)存儲的四種方式之一:Network存儲

三.本地訪問數(shù)據(jù)

將數(shù)據(jù)保存到本地,可以文件流方式寫入sdcard的文件中,也可以通過SharedPreferences方式保存鍵值對,SharedPreferences是一種比較簡單的保存數(shù)據(jù)的方式,封裝成了SharedPreferencesUtils類,更加詳細的使用說明,可以參考《Android開發(fā)之?dāng)?shù)據(jù)存儲的四種方式:SharedPreferences》,這里主要使用文件流的方式將新聞數(shù)據(jù)寫入到sdcard的文件中。

  1. 封裝FileManager工具類
  2. 封裝HttURLConnection工具類
  3. 訪問服務(wù)器,將新聞數(shù)據(jù)寫入文件

FileManager工具類

FileManager工具類傳入需要保存的文件路徑/文件名和文件內(nèi)容,開辟輸出流FileOutputStream/輸入流FileInputStream,寫入到本地sdcard的文件中,涉及到File類的操作:1.創(chuàng)建多級目錄使用mkdirs(),2.創(chuàng)建一級目錄使用mkdir(),3.判斷是否文件目錄isDirectory(),更多使用說明可以參考官方文檔:java.io.File。

  1. public class FileManager {  
  2.     private Context context;  
  3.   
  4.     public FileManager(Context context) {  
  5.         this.context = context;  
  6.     }  
  7.     /** 
  8.      * 存數(shù)據(jù)到sdcard 
  9.      *  
  10.      * @param filename 
  11.      *            :文件名 
  12.      * @param body 
  13.      *            : 文件內(nèi)容 
  14.      */  
  15.     public void saveToSdcard(String filename, String body) throws Exception {  
  16.         /** 
  17.          * 存數(shù)據(jù)到sdcar的實現(xiàn)步驟: 1. 先檢查sdcard狀態(tài) 2. 指定存放的路徑及開辟輸出流,用于存數(shù)據(jù) 3. 把數(shù)據(jù)寫入文件中 4. 
  18.          * 記得加權(quán)限 
  19.          *  
  20.          */  
  21.         if (Environment.getExternalStorageState().equals(  
  22.                 Environment.MEDIA_MOUNTED)) {  
  23.             File rootPath = context  
  24.                     .getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);  
  25.             File file = new File(rootPath, filename);  
  26.   
  27.             // 開辟輸出流  
  28.             FileOutputStream fos = new FileOutputStream(file);  
  29.             fos.write(body.getBytes());  
  30.             fos.close();  
  31.             Toast.makeText(context, '存入手機外部存儲'0).show();  
  32.   
  33.         }else{  
  34.                      Toast.makeText(context, '請插入SDcard!'0).show();  
  35.         }  
  36.   
  37.     }  
  38.   
  39.     /** 
  40.      * 從手機sdcard讀數(shù)據(jù) 
  41.      *  
  42.      * @param filename 
  43.      *            :文件名 
  44.      * @return : FileInputStream :文件輸入流 位置 
  45.      */  
  46.     public String getDataFromSDCard(String filename) throws Exception {  
  47.         if (Environment.getExternalStorageState().equals(  
  48.                 Environment.MEDIA_MOUNTED)) {  
  49.             File rootPath = context  
  50.                     .getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);  
  51.   
  52.             FileInputStream openFileInput = new FileInputStream(rootPath   '/'  
  53.                       filename);  
  54.             BufferedReader bufferedReader = new BufferedReader(  
  55.                     new InputStreamReader(openFileInput));  
  56.             String body = bufferedReader.readLine();// 取得一行  
  57.             openFileInput.close();  
  58.             return body;  
  59.         }  
  60.         return null;  
  61.     }  
  62.           
  63. }  

HttpURLConnection工具類

流分為:字節(jié)流/字符流/文件流/數(shù)組流/緩沖流等,字節(jié)流是流操作的最小單位,字符流以字符為單位,文件流是特定對文件操作的一種流,對于其他的流操作也是字節(jié)流/字符流的直接或間接子類,比如:DataInputStream/DataOutputStream是InputStream/OutputStream的子類,操作方法是對底層流的“包裝”,代碼如下:

  1. InputStream is=new InputSteam();  
  2. DataInputStream dis=new DataInputStream(is);  
  1. OutputStream os=new OutputStream();  
  2. DataOutputStream dos=new DataOutputStream(os);  
  1. /* 
  2.  @author postmaster@ 
  3.  @date 創(chuàng)建于:2016-3-27 
  4.  */  
  5. public class HttpURLConn {  
  6.     private static HttpURLConnection mConnet;  
  7.   
  8.     /** 
  9.      * 單例模式創(chuàng)建HttpURLConnection 
  10.      *  
  11.      * @return 返回HttpURLConnection實例 
  12.      */  
  13.     public static HttpURLConnection newIntance(String url) {  
  14.         if (mConnet == null) {  
  15.             try {  
  16.                 mConnet = (HttpURLConnection) new URL(url).openConnection();  
  17.             } catch (MalformedURLException e) {  
  18.                 e.printStackTrace();  
  19.             } catch (IOException e) {  
  20.                 e.printStackTrace();  
  21.             }  
  22.         }  
  23.         return mConnet;  
  24.     }  
  25.   
  26.     /** 
  27.      * 訪問數(shù)據(jù) 
  28.      *  
  29.      * @return 返回請求的數(shù)據(jù) 
  30.      */  
  31.     public String get() {  
  32.         try {  
  33.             mConnet.setRequestMethod('get');//設(shè)置請求的方式get  
  34.             InputStream is = mConnet.getInputStream();  
  35.             DataInputStream dis = new DataInputStream(is);  
  36.             byte[] bytes = new byte[1024];// 指定每次讀取字節(jié)數(shù)  
  37.             int count = 0;// 記錄每次讀取的位置  
  38.             StringBuffer sb = new StringBuffer();// 保存每次字符  
  39.             String str = null;  
  40.             while ((count = dis.read(bytes)) != -1) {  
  41.                 str = new String(bytes, 0, count);  
  42.                 sb.append(str);  
  43.             }  
  44.             return sb.toString();  
  45.         } catch (IOException e) {  
  46.   
  47.             e.printStackTrace();  
  48.         }  
  49.         return null;  
  50.   
  51.     }  
  52. }  

MainActivity獲取數(shù)據(jù)

調(diào)用HttpURLConn中的get方法訪問服務(wù)器,獲取返回的json數(shù)據(jù),然后o把json寫入本地sdcard文件,再從sdcard的文件中讀取數(shù)據(jù)在ListView中展示,具體代碼如下:

  1. public class MainActivity extends Activity {  
  2.     private static final String TAG = 'MainActivity';  
  3.     private ListView mListView;// 展示新聞的ListView列表  
  4.     private List<NewsBean> mList = new ArrayList<NewsBean>();// 新聞實體  
  5.     private NewsBaseAdapter mAdapter = null;// 新聞適配器  
  6.     /** 
  7.      * 調(diào)用FileManager工具類保存數(shù)到sdcard 
  8.      */  
  9.     private FileManager manager = new FileManager(MainActivity.this);  
  10.     private static final int REFRESH_LISTVIEW = 0x110;  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         mListView = (ListView) findViewById(R.id.news_listview);  
  17.         /** 
  18.          * 獲取服務(wù)器返回的json數(shù)據(jù) 
  19.          */  
  20.         String url[] = { 'http://120.76.76.16:8080/smartpg-1.0/app/cms/listByCode?code=redian&rows=10' };  
  21.         new LoadJsonTask().execute(url);  
  22.   
  23.     }  
  24.   
  25.     @Override  
  26.     protected void onResume() {  
  27.         super.onResume();  
  28.         /** 
  29.          * 從sdcard文件讀取新聞數(shù)據(jù) 
  30.          */  
  31.         try {  
  32.             String json = manager.getDataFromSDCard('json.der');  
  33.             JSONObject obj = new JSONObject(json);  
  34.             String data = obj.getString('data');  
  35.             mList = resolveJson(data);  
  36.             Log.d(TAG, '取出json= '   data);  
  37.         } catch (Exception e) {  
  38.   
  39.             e.printStackTrace();  
  40.         }  
  41.     }  
  42.   
  43.     @Override  
  44.     public boolean onCreateOptionsMenu(Menu menu) {  
  45.         getMenuInflater().inflate(R.menu.main, menu);  
  46.         return true;  
  47.     }  
  48.   
  49.     @Override  
  50.     public boolean onOptionsItemSelected(MenuItem item) {  
  51.         int id = item.getItemId();  
  52.         if (id == R.id.action_settings) {  
  53.             return true;  
  54.         }  
  55.         return super.onOptionsItemSelected(item);  
  56.     }  
  57.   
  58.     private class LoadJsonTask extends AsyncTask<String, Void, String> {  
  59.   
  60.         @Override  
  61.         protected String doInBackground(String... params) {  
  62.             String json = HttpURLConn.newIntance(params[0]).get();  
  63.             if (json == null) {  
  64.                 return '獲取不到數(shù)據(jù)';  
  65.             }  
  66.             return json;  
  67.         }  
  68.   
  69.         @Override  
  70.         protected void onPostExecute(String result) {  
  71.             super.onPostExecute(result);  
  72.             Log.d(TAG, 'result= '   result);  
  73.             /** 
  74.              * 保存新聞數(shù)據(jù)到sdcard 
  75.              */  
  76.             try {  
  77.                 manager.saveToSdcard('json.der', result);  
  78.             } catch (Exception e) {  
  79.                 e.printStackTrace();  
  80.             }             
  81.         }  
  82.   
  83.     }  
  84.   
  85.     private List<NewsBean> resolveJson(String json) {  
  86.         List<NewsBean> mList = new ArrayList<NewsBean>();  
  87.         try {  
  88.             JSONArray mArray = new JSONArray(json);  
  89.             int i = 0;  
  90.             int length = mArray.length();  
  91.             while (i < length) {  
  92.                 JSONObject obj = mArray.getJSONObject(i);  
  93.                 String title = obj.getString('title');  
  94.                 String description = obj.getString('description');  
  95.                 String images = obj.getString('imgUrl');  
  96.                 NewsBean bean = new NewsBean(title, description, images);  
  97.                 mList.add(bean);  
  98.                 i ;  
  99.             }  
  100.             mHandler.sendEmptyMessage(REFRESH_LISTVIEW);  
  101.             return mList;  
  102.         } catch (Exception e) {  
  103.             e.printStackTrace();  
  104.         }  
  105.         return null;  
  106.     }  
  107.   
  108.     Handler mHandler = new Handler() {  
  109.   
  110.         @Override  
  111.         public void handleMessage(Message msg) {  
  112.             // TODO Auto-generated method stub  
  113.             super.handleMessage(msg);  
  114.             switch (msg.what) {  
  115.             case REFRESH_LISTVIEW:  
  116.                 /** 
  117.                  * 刷新新聞列表 
  118.                  */  
  119.                 mAdapter = new NewsBaseAdapter(mList, MainActivity.this);  
  120.                 mListView.setAdapter(mAdapter);  
  121.                 break;  
  122.   
  123.             default:  
  124.                 break;  
  125.             }  
  126.         }  
  127.   
  128.     };  
  129. }  

返回的json類型格式(只羅列一條新聞數(shù)據(jù))如下:

  1. {  
  2.   'code': 'success',  
  3.   'result': '成功',  
  4.   'data': [  
  5.     {  
  6.       'id': 'b78e95f8bb974955aa704496d8a577b2',  
  7.       'isNewRecord': false,  
  8.       'createDate': '2016-01-06 17:31:40',  
  9.       'updateDate': '2016-03-15 15:19:06',  
  10.       'title': '并希望項目負責(zé)人要積極搶抓項目施工的晴好天氣',  
  11.       'link': 'http://120.76.76.16:8080/smartpg-1.0/f/app/cdc4b9b87ac74a5a85806f48cc208890/b78e95f8bb974955aa704496d8a577b2.html',  
  12.       'color': '',  
  13.       'keywords': '',  
  14.       'description': '并希望項目負責(zé)人要積極搶抓項目施工的晴好天氣,加大施工機械和人力組織,確保項目早日建成達產(chǎn)',  
  15.       'weight': 0,  
  16.       'hits': 13,  
  17.       'posid': ',1,',  
  18.       'categoryId': 'cdc4b9b87ac74a5a85806f48cc208890',  
  19.       'imgUrl': 'http://120.76.76.16:8080/smartpg-1.0/userfiles/1/_thumbs/images/cms/article/2016/03/112342amokqmsmpnskfnkm.jpg',  
  20.       'images': [  
  21.         'http://120.76.76.16:8080/smartpg-1.0/userfiles/1/_thumbs/images/cms/article/2016/03/1f1ce870bca48ba3a106b19d1cbce4bc.jpg'  
  22.       ],  
  23.       'offset': 106  
  24.     }  
  25.   ]  
  26. }  

解析JSON格式數(shù)據(jù)使用JSONArray和JSONObject,數(shù)學(xué)將:{}稱為大括號,將:[]稱為中括號,在返回的JSON字符串中,大括號使用JSONObject轉(zhuǎn)換成對象,中括號使用JSONArray轉(zhuǎn)換成對象,例如對面的字符串json,轉(zhuǎn)換代碼如下:

  1. JSONObject obj = new JSONObject(json);  
  2. String data = obj.getString('data');//取出data嵌套的json數(shù)組  
  3. mList = resolveJson(data);  

四.內(nèi)存讀寫數(shù)據(jù)

內(nèi)存讀寫數(shù)據(jù)的位置在:/data/data/ /file,相對本地文件存儲/網(wǎng)絡(luò)存儲,內(nèi)存存儲數(shù)據(jù)的讀寫速度是最快的,在Android開發(fā)中,能夠做到三級緩存的APP,使用起來更加順暢,因為內(nèi)存保存數(shù)據(jù)的位置與當(dāng)前的包名相關(guān),所以需要Context的openFileInput()/openFileOutput()方法獲取輸入/輸出流,而sdcard讀取數(shù)據(jù)使用的是FileInputStream/FileOutputStream類獲取輸入/輸出流,這是他們兩者之間的區(qū)別。具體代碼,如下:

  1.  /**  
  2.      * 存數(shù)據(jù)到內(nèi)存  
  3.      *   
  4.      * @param filename  
  5.      *            :文件名  
  6.      * @param body  
  7.      *            :文件內(nèi)容  
  8.      */  
  9. public void saveToPhone(String filename, String body) throws Exception {  
  10.         /**  
  11.          * 開辟一個輸出流 filename: 文件名 ,有則打開,無則創(chuàng)建 Mode:文件的操作模式 : private: 私有的覆蓋模式 (默認)  
  12.          * 、append : 私有的追加模式 return: FileOutputStream  
  13.          * 文件的路徑:/data/data/<pachagename>/file  
  14.          *   
  15.          */  
  16.         FileOutputStream openFileOutput = context.openFileOutput(filename,  
  17.                 Context.MODE_APPEND);  
  18.         openFileOutput.write(body.getBytes());// 寫字符串到文件輸出流  
  19.         openFileOutput.close();// 關(guān)閉流  
  20. }  
  21.   
  22.         /**  
  23.      * 從內(nèi)存讀數(shù)據(jù)  
  24.      *   
  25.      * @param filename  
  26.      *            :文件名  
  27.      * @return : FileInputStream :文件輸入流 位置:/data/data/<pachagename>/file  
  28.      */  
  29. public String getDataFromPhone(String filename) throws Exception {  
  30.   
  31.         FileInputStream openFileInput = context.openFileInput(filename);  
  32.         BufferedReader bufferedReader = new BufferedReader(  
  33.                 new InputStreamReader(openFileInput));  
  34.         String body = bufferedReader.readLine();// 取得一行  
  35.         openFileInput.close();  
  36.         return body;  
  37. }  

可以將上面新聞中的數(shù)據(jù)同時保存到內(nèi)存/sdcard,當(dāng)啟動APP時,首先從內(nèi)存讀取,如果內(nèi)存的數(shù)據(jù)不存在,再從sdcard中讀取,最后
從網(wǎng)絡(luò)加載,這是三級緩存的開發(fā)思路,結(jié)合上面的Demo,完成新聞列表的展示。

五.下一篇文章將介紹《如何讀寫sqlite數(shù)據(jù)庫中的新聞數(shù)據(jù)》

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多