電子市場項目總結(四)
1、網絡數據解析的封裝
這部分代碼沒有什麼靈活性可言,如果能熟練使用BaseAdapter的封裝,這裏對網絡數據的解析封裝相對就非常簡單了!
直接從代碼入手:
public abstract class BaseProtocol<T> {
// 這裏是複習如何使用enum枚舉,因爲服務器中對請求有一下幾種所以封裝起來更方便使用
public enum Key {
category("category"), image("image"), recommend("recommend"), subject("subject"),
detail("detail"), home("home"), app("app"), game("game"), download("download"),
user("user"), hot("hot");
String key;
private Key(String key) {
this.key = key;
}
public String getKey() {
return this.key;
}
}
private String mKey;
/**
* 根據position進行分頁查詢,
* 此處的分頁查詢是因爲服務器已經支持分頁查詢的功能,因此只需要填充對應的position即可,
* 這裏有一點,position在數據的連續的情況下可以直接使用list的總數,
* 即調用者直接填充已經獲取的數據的個數。
*/
public T getData(int position) {
mKey = setKey().getKey();
if (StringUtils.isEmpty(mKey))
return null;
mKey = mKey + "?index=" + position + getParams();
// 先從本地緩存中讀取,如果沒有讀取到才網絡加載
String dataString = readCache(position);
if (StringUtils.isEmpty(dataString)) {
dataString = readInternet(position);
}
return parseData(dataString);
}
/**
* 提供給子類設置參數
*
*/
protected abstract String getParams();
/**
* 子類實現數據的解析
*
*/
protected abstract T parseData(String dataString);
/**
* 子類必須實現key,來確認訪問地址
*
*/
public abstract Key setKey();
/**
* 從網絡中獲取數據,這裏網絡的解析在HttpHelper類中被封裝好了,直接拿來使用即可,
* HttpHelper中使用的HttpClient,api23以上需要導入path:sdk\platforms\android-23\optional\org.apache.http.legacy.jar包,當然也可使用其他新的框架來封裝。
*/
private String readInternet(int position) {
// 獲取連接對象
HttpHelper.HttpResult httpResult = HttpHelper.get(HttpHelper.URL + mKey);
// 獲取json數據
String string = "";
if (httpResult != null)
string = httpResult.getString();
LogUtils.i(string);
// 如果非空
if (!StringUtils.isEmpty(string)) {
saveCache(string);
}
return string;
}
/**
* 保存數據到本地,並添加有效期,添加有效期這裏可以有兩種方式,
* 一種是直接添加截止期,讀取時判斷是否超過截止期,
* 另一種是添加生成的日期,去讀時將讀取時間減去生成時間,判斷是否超過有效期。
*/
private void saveCache(String data) {
String cacheDir = MyApplication.getContext().getExternalCacheDir().getAbsolutePath() + File.separator + "jsondata";
File file = new File(cacheDir);
if (!file.exists()) {
file.mkdirs();
file.setReadable(true);
file.setWritable(true);
}
FileWriter fileWriter = null;
try {
file = new File(file, CommonUtil.data2MD5(mKey, ""));
if (file.exists()) {
file.delete();
file.createNewFile();
file.setReadable(true);
file.setWritable(true);
}
fileWriter = new FileWriter(file);
// 寫上時間標記
// fileWriter.write(System.currentTimeMillis()+30*1000*60+"\n"); 自帶截止日期
fileWriter.write(System.currentTimeMillis() + "\n");
fileWriter.write(data);
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(fileWriter);
}
}
/**
* 從本地中讀取緩存
*/
private String readCache(int position) {
String data = "";
String cacheDir = MyApplication.getContext().getExternalCacheDir().getAbsolutePath() + File.separator + "jsondata" + File.separator + CommonUtil.data2MD5(mKey, "");
File file = new File(cacheDir);
BufferedReader br = null;
if (file.exists()) {
try {
br = new BufferedReader(new FileReader(file));
// 讀取日期
long date = Long.parseLong(br.readLine());
// 在有效期內才使用
if (System.currentTimeMillis() - date < 1800000) {
String line;
while ((line = br.readLine()) != null) {
data = data + line;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
}
那麼這些完成後,子類該實現的方法有:
- protected abstract String getParams();// 提供給子類設置參數
- protected abstract T parseData(String dataString);//子類實現數據的解析邏輯
- public abstract Key setKey();//子類必須實現key,來確認訪問地址
2、開始實現一個Fragment
網絡協議也已經封裝完成子類只需要完成對網絡數據的解析即可,那麼開始將封裝完成的Protocol、BaseFragment、MyBaseAdapter以及BaseViewHolder結合起來就可以構建一個Fragment的了。
代碼如下:
public class AppFragment extends BaseFragment {
private List<AppInfo> mListData = new ArrayList<>();
private String tag = "AppFragment";
private MyListView mMyListView;
private InnerAdapter mAdapter;
private AppProtocol mAppProtocol;
/**
* 數據的刷新會在fragment繪製之前被調用
*/
protected State loadData() {
if(mAppProtocol==null)
mAppProtocol = new AppProtocol();
mListData = mAppProtocol.getData(0);
return checkLoad(mListData);
}
/**
沒有使用到監聽
*/
protected void initListener() {
// empty
}
/**
完成一個佈局的記載,可以直接返回一個listView即可
*/
public View initSuccessLayout() {
mMyListView = new MyListView(mActivity);
mAdapter = new InnerAdapter(mListData);
mMyListView.setAdapter(mAdapter);
return mMyListView;
}
/**
我們已經完成BaseAdapter的封裝,所以我們只需要提供數據就可以實現數據的加載和展現
*/
private class InnerAdapter extends MyBaseAdapter<AppInfo>{
public InnerAdapter(List<AppInfo> mDataList) {
super(mDataList);
}
@Override
protected List<AppInfo> loadingMore() {
if(mAppProtocol!=null)
return mAppProtocol.getData(mListData.size());
return null;
}
@Override
protected BaseViewHolder<AppInfo> getBaseViewHolder(int position) {
return new AppHolder();
}
}
}