谷歌市场项目代码详解(二)

网络请求的封装

<span style="font-size:18px;">public class NetUtil {

	protected static final Object TAG = NetUtil.class;

	public static void requestData(String url, TreeMap<String, String> params, JsonRequestCallback jsonRequestCallback) {
		//拼接网址
		String requestUrl = createUrl(url,params);
		//获取缓存文件
		File cacheFile = getCacheFile(requestUrl);
		//判断缓存文件是否有效
		if (cacheFileVaild(cacheFile)) {//如果有效 读取缓存文件
			getDataFromCache(cacheFile,jsonRequestCallback);
		}else {	//如果无效 则访问网络
			getDataFromNet(requestUrl,jsonRequestCallback);
		}
		
	}

	/**拼接网络链接*/
	private static String createUrl(String url, TreeMap<String, String> params) {
		
		if (params == null || params.isEmpty()) {
			return url;
		}
		
		StringBuffer sb = new StringBuffer();
		
		//遍历map集合的键的集合
		for (String key : params.keySet()) {
			sb.append("&").append(key).append("=").append(params.get(key));
		}
		sb.deleteCharAt(0);//删除第一个元素
		String requestUrl = url + "?" + sb.toString();
		return requestUrl;
	}

	/**获取缓存文件*/
	private static File getCacheFile(String requestUrl) {
		
		//将网址进行编码  去掉特殊字符 这样就可以作为文件名了
		String cacheFileName;
		try {
			cacheFileName = URLEncoder.encode(requestUrl, HTTP.UTF_8);
			File cacheFile = new File(MyApp.getContext().getCacheDir(),cacheFileName);
			return cacheFile;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**判断缓存文件是否有效,不存在  或 为空  或超时 都视为无效*/
	private static boolean cacheFileVaild(File cacheFile) {
		if (cacheFile == null || !cacheFile.exists()) {
			return false;
		}
		//获取文件最后修改时间
		long  lastModifyTime = cacheFile.lastModified();
		//定义有效时间为三分钟
		long vaildExistsTime = 3 * 60 * 1000;
		
		boolean isVaild = lastModifyTime < vaildExistsTime;
		return isVaild;
	}

	/**获取网路数据
	 * @param jsonRequestCallback */
	private static void getDataFromNet(final String requestUrl, final JsonRequestCallback jsonRequestCallback) {
		HttpUtils httpUtils = new HttpUtils();
		RequestCallBack<String> callBack = new RequestCallBack<String>() {

			@Override
			public void onSuccess(ResponseInfo<String> responseInfo) {
				String json = responseInfo.result;
				Logger.i(TAG, responseInfo.result);
				//保存缓存数据
				cacheData(requestUrl,json);
				jsonRequestCallback.onRequestFinish(json);
			}

			@Override
			public void onFailure(HttpException error, String msg) {
				Logger.e(TAG, "请求网络数据失败:" + msg, error);
				jsonRequestCallback.onRequestFinish(null);
				
			}
		};
		httpUtils.send(HttpMethod.GET, requestUrl, callBack );
	}

	/**保存缓存数据*/
	protected static void cacheData(String requestUrl, String json) {
	
		if (json == null) {
			return;
		}
		BufferedWriter bw = null;
		try {
			//获取缓存文件
			File cacheFile = getCacheFile(requestUrl);
			//写json到缓存文件
			bw = new BufferedWriter(new FileWriter(cacheFile));
			bw.write(json);
			bw.flush();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			IOUtils.closeQuietly(bw);
		}		
		
	}

	/**读取缓存中的数据,  在子线程中进行
	 * @param jsonRequestCallback */
	private static void getDataFromCache(final File cacheFile, final JsonRequestCallback jsonRequestCallback) {
		new AsyncTask<Void, Void, String>() {

			@Override
			protected String doInBackground(Void... params) {
				BufferedReader br = null;
				StringBuffer sb = new StringBuffer();
				try {
					 br = new BufferedReader(new FileReader(cacheFile));
					 String line = null;
					 while((line = br.readLine()) != null){
						 sb.append(line).append("\n");
					 }
					 return sb.toString();
				} catch (Exception e) {
					e.printStackTrace();
				}finally{
					IOUtils.closeQuietly(br);
				}
				return null;
			}
			
			/**获取数据完毕后 接受返回的数据并处理*/
			protected void onPostExecute(String result) {
				Logger.i(TAG, "接受到的json数据为:" + result);
				jsonRequestCallback.onRequestFinish(result);
				
			};
		}.execute();
		
	}

}</span>

Json解析

Json的解析使用开源的gson-2.2.4.jar进行解析即可,把资料中的gson-2.2.4.jar复制libs目录中,再把资料中的JsonUtil.java复制到项目中的util包中,JsonUtil中有两个方法,一个是jsonToBean方法需要把json转换JavaBean对象时调用此方法(Json数据的根元素就是一个对象),另个方法是json2Collection方法,当需要把json转换为一个集合对象的时候使用该方法Json数据的根元素就是一个集合)。解析首页的数据,如下:

public void onRequestFinish(String json) {
	HomeBean homeBean = JsonUtil.json2Bean(json, HomeBean.class);
		
	ArrayList<AppInfo> datas = null;
	if (homeBean != null) {
		datas = homeBean.list;	// 获取首页数据列表
	}
		
	// 根据服务器返回的数据情况判断需要显示的View
	if (datas == null) {
		stateLayout.showFailView();
	} else if (datas.isEmpty()) {
		stateLayout.showEmptyView();
	} else {
		stateLayout.showContentView();
	}

实现下拉刷新和上拉加载更多


可以使用开源类库”PullToRefresh”,导入资料中的“PullToRefreshLibrary”,

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <com.handmark.pulltorefresh.library.PullToRefreshListView 
        android:id="@+id/ptr_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    
</LinearLayout>

初始化HeaderViewFooterView中显示的文字,在initView中调用下面的方法

private void initHeaderAndFooter() {
	ptr_list_view.setMode(Mode.BOTH);	// 设置可以下拉也可以下拉
	boolean includeStart = true;
	boolean includeEnd = false;
	headerView = ptr_list_view.getLoadingLayoutProxy(includeStart, includeEnd);
	headerView.setPullLabel("下拉以刷新");
	headerView.setReleaseLabel("松开以刷新");
	headerView.setRefreshingLabel("正在刷新...");
		
	includeStart = false;
	includeEnd = true;
	footerView = ptr_list_view.getLoadingLayoutProxy(includeStart, includeEnd);
	footerView.setPullLabel("上拉加载更多");
	footerView.setReleaseLabel("松开以加载更多");
	footerView.setRefreshingLabel("正在加载更多...");
}

增加下拉、上拉监听器

public void initListener() {
	ptr_list_view.setOnRefreshListener(new OnRefreshListener<ListView>() {

		@Override
		public void onRefresh(PullToRefreshBase<ListView> refreshView) {
			initData();
		}
	});
}

获取数据的时候要判断是上拉还是下拉:

public void initData() {
	TreeMap<String, String> params = new TreeMap<String, String>();
	int index;
	if (ptr_list_view.getCurrentMode() == Mode.PULL_FROM_START) {
		index = 0;	// 如果是下拉刷新,则都是获取第0页
	} else {
		index = adapter.getCount();
	}
	params.put("index", index + "");
	MyRequestListener requestListener = new MyRequestListener();
	NetUtil.requestData(Urls.HOME, params, HomeBean.class, null, requestListener);
}

在获取到数据的地方也要做相应处理,如下:

public void onRequestFinish(String json) {
	HomeBean homeBean = JsonUtil.json2Bean(json, HomeBean.class);
		
	ArrayList<AppInfo> datas = null;
	if (homeBean != null) {
		datas = homeBean.list;	// 获取首页数据列表
	}
		
	if (ptr_list_view.getCurrentMode() == Mode.PULL_FROM_START) {
		// 根据服务器返回的数据情况判断需要显示的View
		if (datas == null) {
			stateLayout.showFailView();
		} else if (datas.isEmpty()) {
			stateLayout.showEmptyView();
		} else {
			stateLayout.showContentView();
			adapter.getDatas().clear();		// 如果是下拉刷新,则把之前的数据先清空
			adapter.getDatas().addAll(datas);
			adapter.notifyDataSetChanged();
			ptr_list_view.onRefreshComplete();
			CharSequence lastUpdateTime = DateFormat.format("最后更新于:MM-dd kk:mm:ss", new Date());
			headerView.setLastUpdatedLabel(lastUpdateTime);
		}
	} else {
		// 如果是上拉加载更多
		if (datas != null && !datas.isEmpty()) {
			adapter.getDatas().addAll(datas);
			adapter.notifyDataSetChanged();
			ptr_list_view.onRefreshComplete();
		}
	}
}

Fragment获取到数据后都要根据数据的不同情况决定显示对应状态的View操作可以抽取到BaseFragment中,方便各个Fragment复用,如下:

/**  检查初始化数据,根据数据的不同情况显示对应状态的View */
public boolean checkData(Collection<?> datas) {
	boolean result = false;
	if (datas == null) {
		stateLayout.showFailView();
	} else if (datas.isEmpty()) {
		stateLayout.showEmptyView();
	} else {
		stateLayout.showContentView();
		result = true;
	}
	return result;
}


对BaseAdapter的抽取

<span style="font-size:18px;">public abstract class MyBaseAdapter<T> extends BaseAdapter {
	public  List<T> datas;
	public MyBaseAdapter(List<T> datas) {
		this.datas = datas;
	}

	public List<T>  getDatas(){
		if (datas == null) {
			datas = new ArrayList<T>();
		}
		return datas;
	}
	@Override
	public int getCount() {
		return datas == null?0:datas.size();
	}

	@Override
	public Object getItem(int position) {
		return datas.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Object holder = null ;
		if (convertView == null) {
			convertView = View.inflate(parent.getContext(), getLayoutId(position), null);
			holder = getHolderAndFindViewById(convertView,position);
			convertView.setTag(holder);
		} else {
			holder = convertView.getTag();
		}
		
		T data = datas.get(position);
		
		showData(holder,data,position);
		return convertView;
	}

	public abstract void showData(Object holder, T data, int position);

	public abstract Object getHolderAndFindViewById(View convertView, int position);

	public abstract int getLayoutId(int position);

}</span><span style="font-size:32px;font-weight: bold;">
</span>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值