电子市场项目总结(四)
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();
}
}
}