操作的模式和app的显示类似,首先创建一个SubjectProtacal来请求服务器的json资源并解析,然后在SubjectFragment中通过ListView显示
由于HomeProtacal和SubjectProtacal请求中网络请求,保存在本地以及本地资源的加载都是类似的,解析不是类似的,因此现在将共性封装成BaseProtacal,在BaseProtacal.java中通过泛型来初始化相关的数据
同时,图片资源显示的BitmapUtils也是需要每次去创建,可以在BaseFragment中直接去创建避免在HomeFragment和SubjectFragment中重复创建,请求的数据的校检也在BaseFragment中实现,因为每一组数据的请求都会去校检
BaseFragment.java
package com.ldw.market.fragment;
import java.util.List;
import com.ldw.market.R;
import com.ldw.market.domain.AppInfo;
import com.ldw.market.manager.ThreadManager;
import com.ldw.market.utils.BitmapHelper;
import com.ldw.market.utils.ViewUtils;
import com.lidroid.xutils.BitmapUtils;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
public abstract class BaseFragment extends Fragment {
//初始化页面加载的5种状态
public static final int STATE_UNKOWN = 0;
public static final int STATE_LOADING = 1;
public static final int STATE_ERROR = 2;
public static final int STATE_EMPTY = 3;
public static final int STATE_SUCCESS = 4;
public int state = STATE_UNKOWN;
private View loadingView;// 加载中的界面
private View errorView;// 错误界面
private View emptyView;// 空界面
private View successView;// 加载成功的界面
private FrameLayout frameLayout;
protected BitmapUtils bitmapUtils;
//创建一个View对象
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
bitmapUtils = BitmapHelper.getBitmapUtils();
if(frameLayout == null){
frameLayout = new FrameLayout(getActivity());
init(); // 在FrameLayout中 添加4种不同的界面:加载中, 加载错误,加载为空 ,加载成功
}else{
ViewUtils.removeParent(frameLayout);
}
//show();// 根据服务器的数据 切换状态
return frameLayout;
}
// 在FrameLayout中 添加4种不同的界面:加载中, 加载错误,加载为空 ,加载成功
private void init() {
// 创建了加载中的界面
loadingView = createLoadingView();
if (loadingView != null) {
frameLayout.addView(loadingView, new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
// 加载错误界面
errorView = createErrorView();
if (errorView != null) {
frameLayout.addView(errorView, new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
// 加载空的界面
emptyView = createEmptyView();
if (emptyView != null) {
frameLayout.addView(emptyView, new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
// 根据不同的状态显示不同的界面
showPage();
}
//根据不同的状态显示不同的界面
private void showPage(){
//利用||,显示加载界面
if (loadingView != null) {
loadingView.setVisibility(state == STATE_UNKOWN
|| state == STATE_LOADING ? View.VISIBLE : View.INVISIBLE);
}
//利用||,显示错误界面
if (errorView != null) {
errorView.setVisibility(state == STATE_ERROR ? View.VISIBLE
: View.INVISIBLE);
}
//利用||,显示空界面
if (emptyView != null) {
emptyView.setVisibility(state == STATE_EMPTY ? View.VISIBLE
: View.INVISIBLE);
}
if (state == STATE_SUCCESS) {
//创建成功的时候加载成功页面
if (successView == null) {
//为空的时候创建View
successView = createSuccessView();
frameLayout.addView(successView, new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
successView.setVisibility(View.VISIBLE);
}
}else{
//不成功的时候让页面隐藏
if(successView != null){
successView.setVisibility(View.INVISIBLE);
}
}
}
//加载成功的界面
public abstract View createSuccessView();
/* 创建加载中的界面 */
private View createErrorView() {
View view = View.inflate(getActivity(), R.layout.loadpage_error, null);
//点击按钮重新请求服务器更新界面
Button page_bt = (Button) view.findViewById(R.id.page_bt);
page_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
show();
}
});
return view;
}
/* 加载错误界面 */
private View createEmptyView() {
View view = View.inflate(getActivity(), R.layout.loadpage_empty, null);
return view;
}
/* 加载空的界面 */
private View createLoadingView() {
View view = View.inflate(getActivity(), R.layout.loadpage_loading, null);
return view;
}
//更具服务器获取的状态显示界面
public void show() {
//更新状态,当加载错误以后或者加载了空页面时候需要更新一下状态
if (state == STATE_ERROR || state == STATE_EMPTY) {
state = STATE_LOADING;
}
// 请求服务器 获取服务器上数据 进行判断
// 请求服务器 返回一个结果
//子线程中请求服务器,同时休眠一下
//使用线程池管理
ThreadManager.getInstance().createLongPool().execute(new Runnable(){
@Override
public void run() {
//休眠2s
SystemClock.sleep(2000);
final LoadResult result = load();
//主线程刷新界面
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if(result != null){
//更新状态
state = result.getValue();
//更新界面
showPage();
}
}
});
}
});
showPage();
}
//服务器返回的数据
protected abstract LoadResult load();
//服务器返回的枚举结果,来显示界面
public enum LoadResult{
error(2), empty(3), success(4);
int value;
//获取服务器返回的结果
LoadResult(int value) {
this.value = value;
}
//获取到value
public int getValue() {
return value;
}
}
//校验数据
public LoadResult checkData(List datas){
if(datas == null){
return LoadResult.error;//请求服务器数据失败
}else{
if(datas.size() == 0){
return LoadResult.empty;
}else{
return LoadResult.success;
}
}
}
}
BaseProtocol.java网络请求共性部分抽取出来,json数据的解析各个子类自己实现package com.ldw.market.protocol;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.StringWriter;
import com.ldw.market.http.HttpHelper;
import com.ldw.market.http.HttpHelper.HttpResult;
import com.ldw.market.utils.FileUtils;
import com.lidroid.xutils.util.IOUtils;
public abstract class BaseProtocol<T> {
public T load(int index) {
// 加载本地数据
String json = loadLocal(index);
if (json == null) {
// 请求服务器
json = loadServer(index);
if (json != null) {
saveLocal(json, index);
}
}
if (json != null) {
return parseJson(json);
} else {
return null;
}
}
//从服务器请求json数据
private String loadServer(int index) {
//请求地址http://127.0.0.1:8090/home?index=1
HttpResult httpResult = HttpHelper.get(HttpHelper.URL + getKey()
+ "?index=" + index);
//得到结果
String json = httpResult.getString();
//System.out.println(json);
return json;
}
//将json保存在本地:方法1把整个json文件写到一个本地文件中,方法2吧每条数据都摘出来保存在数据库中
private void saveLocal(String json, int index) {
//创建一个buffer
BufferedWriter bw = null;
try {
File dir=FileUtils.getCacheDir();
//创建一个文件
File file = new File(dir, getKey() + "_" + index); // /mnt/sdcard/market/cache/home_0
FileWriter fw = new FileWriter(file);
bw = new BufferedWriter(fw);
//在第一行写一个过期时间
bw.write(System.currentTimeMillis() + 1000 * 100 + "");
bw.newLine();// 换行
bw.write(json);// 把整个json文件保存起来
bw.flush();
bw.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
IOUtils.closeQuietly(bw);
}
}
//加载本地保存的数据
private String loadLocal(int index) {
// 如果发现时间过期了,就不用本地的缓存
File dir=FileUtils.getCacheDir();// 获取缓存所在的文件夹
//得到缓存文件
File file = new File(dir, getKey() + "_" + index);
try {
FileReader fr=new FileReader(file);
BufferedReader br=new BufferedReader(fr);
//获取过期时间
long outOfDate = Long.parseLong(br.readLine());
//判断是否过期,
if(System.currentTimeMillis()>outOfDate){
return null;
}else{
String str=null;
StringWriter sw=new StringWriter();
while((str=br.readLine())!=null){
sw.write(str);
}
return sw.toString();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 解析json
* @param json
* @return
*/
public abstract T parseJson(String json);
/**
* 说明了关键字home,subject....
*/
public abstract String getKey();
}
SubjectBean.java这里是subject的bean
package com.ldw.market.domain;
public class SubjectInfo {
private String des;
private String url;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String toString() {
return "SubjectInfo [des=" + des + ", url=" + url + "]";
}
public SubjectInfo() {
super();
}
public SubjectInfo(String des, String url) {
super();
this.des = des;
this.url = url;
}
}
SubjectProtocol.javapackage com.ldw.market.protocol;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.ldw.market.domain.AppInfo;
import com.ldw.market.domain.SubjectInfo;
/*
* SubjectProtocol网络请求
*/
public class SubjectProtocol extends BaseProtocol <List<SubjectInfo>>{
@Override
public List<SubjectInfo> parseJson(String json) {
List<SubjectInfo> subjectInfos=new ArrayList<SubjectInfo>();
try {
//[]需要JSONArray
JSONArray jsonArray=new JSONArray(json);
for(int i=0;i<jsonArray.length();i++){
//大括号需要getJSONObject,获取到大括号对象
JSONObject jsonObject = jsonArray.getJSONObject(i);
String des=jsonObject.getString("des");
String url = jsonObject.getString("url");
SubjectInfo info=new SubjectInfo(des, url);
subjectInfos.add(info);
}
return subjectInfos;
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
@Override
public String getKey() {
return "subject";
}
}
HomeProtocal.javapackage com.ldw.market.protocol;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.ldw.market.domain.AppInfo;
import com.ldw.market.http.HttpHelper;
import com.ldw.market.http.HttpHelper.HttpResult;
import com.ldw.market.utils.FileUtils;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseStream;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;
import com.lidroid.xutils.util.IOUtils;
public class HomeProtocal extends BaseProtocol <List<AppInfo>>{
//解析json数据
public List<AppInfo> parseJson(String json) {
List<AppInfo> appInfos = new ArrayList<AppInfo>();
try {
JSONObject jsonObject = new JSONObject(json);
//获取到中括号的内容
JSONArray jsonArray = jsonObject.getJSONArray("list");
//遍历list数组,list数组里面又是由大括号构成
for(int i = 0; i < jsonArray.length(); i++){
JSONObject jsonObj = jsonArray.getJSONObject(i);
long id = jsonObj.getLong("id");
String name = jsonObj.getString("name");
String packageName = jsonObj.getString("packageName");
String iconUrl = jsonObj.getString("iconUrl");
float stars = Float.parseFloat(jsonObj.getString("stars"));
long size = jsonObj.getLong("size");
String downloadUrl = jsonObj.getString("downloadUrl");
String des = jsonObj.getString("des");
//构造函数,创建一个appInfo
AppInfo appInfo = new AppInfo(id, name, packageName, iconUrl,
stars, size, downloadUrl, des);
//往集合中添加对象
appInfos.add(appInfo);
}
return appInfos;
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
@Override
public String getKey() {
// TODO Auto-generated method stub
return "home";
}
}
SubjectFragment.javapackage com.ldw.market.fragment;
import java.util.List;
import com.ldw.market.R;
import com.ldw.market.domain.SubjectInfo;
import com.ldw.market.fragment.BaseFragment.LoadResult;
import com.ldw.market.http.HttpHelper;
import com.ldw.market.protocol.SubjectProtocol;
import com.ldw.market.utils.BitmapHelper;
import com.ldw.market.utils.UiUtils;
import com.lidroid.xutils.BitmapUtils;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class SubjectFragment extends BaseFragment {
private List<SubjectInfo> datas;
@Override
public View createSuccessView() {
ListView listView=new ListView(UiUtils.getContext());
listView.setAdapter(new SubjectAdapter());
return listView;
}
private class SubjectAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return datas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return datas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder;
if(convertView==null){
view=View.inflate(UiUtils.getContext(), R.layout.item_subject, null);
holder=new ViewHolder();
holder.item_icon=(ImageView) view.findViewById(R.id.item_icon);
holder.item_txt=(TextView) view.findViewById(R.id.item_txt);
view.setTag(holder);
}else{
view=convertView;
holder=(ViewHolder) view.getTag();
}
SubjectInfo info=datas.get(position);
holder.item_txt.setText(info.getDes());
bitmapUtils.display(holder.item_icon, HttpHelper.URL+"image?name="+info.getUrl());
return view;
}
}
class ViewHolder{
ImageView item_icon;
TextView item_txt;
}
@Override
protected LoadResult load() {
SubjectProtocol protocol=new SubjectProtocol();
datas = protocol.load(0);
return checkData(datas);
}
}
subject页面的布局文件item_subject<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="9dip"
android:layout_marginRight="9dip"
android:background="@drawable/list_item_bg" >
<ImageView
android:id="@+id/item_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:src="@drawable/ic_default"
android:padding="5dp"/>
<TextView
android:id="@+id/item_txt"
style="@style/TitleStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_below="@id/item_icon"
android:gravity="center_vertical"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:singleLine="true" />
</RelativeLayout>
</FrameLayout>
在res/values/styles.xml中添加样式 <style name="TitleStyle">
<item name="android:textColor">@color/txt_title</item>
<item name="android:textSize">@dimen/list_item_title_size</item>
<item name="android:ellipsize">end</item>
<item name="android:singleLine">true</item>
</style>
res/values/demons.xml中设置大小<dimen name="list_item_title_size">16dp</dimen>
res/values/colors.xml中设置颜色<color name="txt_title">#333333</color>