在上文: AsyncTask解析(上)——原理分析与超简单demo实现中已经对AsyncTask的实现原理以及源码流程进行了一定的分析,相信大家已经基本熟悉了AsyncTask内部实现网络传输的调用顺序以及过程细节,最后还写出了一个比较简单的Demo实践,十分简单易懂相信大家都能很快掌握。
然而那个Demo还是太粗制滥造了,功能太缺乏,很多需要传入的参数也没有写到构参里直接给写死了..
并且在真正的项目实践中,光使用这个简单的Demo是远远不够的,我们需要对它进行更好的封装,扩展它的功能,才能更好地为我们的项目服务。
所以,本文的核心重点是如何去封装出一个AsyncTask工具类,以及如何让AsyncTask变得简单易用。
整体框架的继承关系如下图所示:
理清一下思路,整体框架应用观察者模式,可以细分为以下几个步骤:
1、实现一个抽象类UrlAsyNet继承AsyncTask<String,Integer,T>(这里第三个参数设置为T是为了适配不同的传输类型)。
这里为什么不用接口呢?因为接口的方法是不能有具体的实现的,但是在该方法中需要进行初始化的工作,所以这里使用了抽象类来实现。
/**
* Created by nangua on 2016/4/26.
* Params 启动任务执行的输入参数,这里是URL所以用String
* Progress 后台任务执行的百分比。
* Result 后台执行任务最终返回的结果,比如String。
*/
public class UrlAsyNet<T> extends AsyncTask<String,Integer,T> {
/**
* 全部参数构造方法
* @param apikey
* @param httpArg
* @param httpUrl
* @param method
* @param onNetStateChangedListener
* @param type
*/
public UrlAsyNet(String apikey, String httpArg, String httpUrl, NetMethod method, OnNetStateChangedListener<T> onNetStateChangedListener, ParamType type) {
this.apikey = apikey;
this.httpArg = httpArg;
this.httpUrl = httpUrl;
this.method = method;
this.onNetStateChangedListener = onNetStateChangedListener;
this.type = type;
}
/**
* 传入URL
* @param httpUrl
*/
public UrlAsyNet(String httpUrl,String apikey,String httpArg) {
this.httpUrl = httpUrl;
this.apikey = apikey;
this.httpArg = httpArg;
}
//添加枚举类型
public enum NetMethod{
GET,POST
}
/**
* 参数类型。分为:JSONorXML文件。键值对,无参
*/
public enum ParamType{
JSON_OR_XML_FILE
,KEY_VALUE_PAIR,
NO_PARAM
}
/**
* 网络状态改变时候的监听器
* @param <T>
*/
public interface OnNetStateChangedListener<T> {
/**
* 访问网络之前
*/
public void beforeAccessNet();
/**
* 访问网络成功获取数据之后
*
* @param result
*/
public void afterAccessNet(T result);
/**
* 出现了错误的时候
*/
public void whenException();
/**
* 执行进度
* @param progress
*/
public void onProgress(Integer progress);
}
//设置监听器回调
public OnNetStateChangedListener<T> getOnNetStateChangedListener() {
return onNetStateChangedListener;
}
//设置网络监听器
public void setOnNetStateChangedListener(OnNetStateChangedListener<T> onNetStateChangedListener) {
this.onNetStateChangedListener = onNetStateChangedListener;
}
//网络监听器实例
OnNetStateChangedListener<T> onNetStateChangedListener;
//在四个回调方法中调用网络监听器的方法以实现回调
@Override
protected void onCancelled() {
if (onNetStateChangedListener!=null){
onNetStateChangedListener.whenException();
}
}
@Override
protected void onPostExecute(T t) {
if (onNetStateChangedListener!=null){
onNetStateChangedListener.afterAccessNet(t);
}
}
@Override
protected void onPreExecute() {
if (onNetStateChangedListener!=null){
onNetStateChangedListener.beforeAccessNet();
}
}
@Override
protected void onProgressUpdate(Integer... values) {
if (onNetStateChangedListener!=null){
if (values.length>1) {
onNetStateChangedListener.onProgress(values[0]);
}
}
}
//使用HttpURLConnection需要用到的httpUrl
String httpUrl ;
//使用HttpURLConnection需要用到的httpArg
String httpArg ;
//连接百度API需要的APIKEY
String apikey;
//得到的参数类型
ParamType type;
//网络请求参数(GET或POST)
NetMethod method;
//数据
String jsonOrXmlFile;
//键值对
HashMap<String, Object> keyValuePair;
public String getHttpUrl() {
return httpUrl;
}
public void setHttpUrl(String httpUrl) {
this.httpUrl = httpUrl;
}
public String getApikey() {
return apikey;
}
public void setApikey(String apikey) {
this.apikey = apikey;
}
public String getHttpArg() {
return httpArg;
}
public void setHttpArg(String httpArg) {
this.httpArg = httpArg;
}
public ParamType getType() {
return type;
}
public void setType(ParamType type) {
this.type = type;
}
@Override
protected T doInBackground(String... params) {
return null;
}
/**
* 执行
*/
public void execute(){
this.execute(new String[]{});
}
}
2、在抽象类里编写一个网络监听器接口。然后在需要使用到的地方(比如在MainActivity里需要使用,就在MainActivity里写一个实现这个接口的内部类,从而在这个内部类里实现随着网络状态的改变改变对UI的操作)。
那么问题来了:这里为什么不把组件当做参数传进去呢?比如在上文中的Demo是把TextView和ProgressBar传进去的,那么如果你要传入的是一个CustView呢?这样就得重新修改写好的代码,拆轮子,违背了程序的可扩展性。所以更好的办法是提供一个可实现的网络监听接口,在接口里进行更新UI操作。
/**
* 网络状态改变时候的监听器
* @param <T>
*/
public interface OnNetStateChangedListener<T> {
/**
* 访问网络之前
*/
public void beforeAccessNet();
/**
* 访问网络成功获取数据之后
*
* @param result
*/
public void afterAccessNet(T result);
/**
* 出现了错误的时候
*/
public void whenException();
/**
* 执行进度
* @param progress
*/
public void onProgress(Integer progress);
}
网络监听器的代码上文已经出现了,这里单独列出来一下。
3、编写具体的工具类UrlNormalAsyNet,实现对数据的接受(暂时没有写JSON和XML的解析):
/**
* Created by nangua on 2016/4/26.
*/
public class UrlNormalAsyNet extends UrlAsyNet<String>{
/**
* 请求方法POST和get
*/
AsyNet.NetMethod method;
public UrlNormalAsyNet(String apikey, String httpArg, String httpUrl, NetMethod method, OnNetStateChangedListener<String> onNetStateChangedListener, ParamType type) {
super(apikey, httpArg, httpUrl, method, onNetStateChangedListener, type);
}
public UrlNormalAsyNet(String httpUrl, String apikey, String httpArg) {
super(httpUrl, apikey, httpArg);
this.httpUrl = httpUrl;
this.apikey = apikey;
this.httpArg = httpArg;
}
@Override
protected String doInBackground(String... params) {
BufferedReader reader = null;
String result = null;
StringBuffer sbf = new StringBuffer();
httpUrl = httpUrl + "?" + httpArg;
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("apikey", apikey);
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = null;
while ((strRead = reader.readLine()) != null) {
sbf.append(strRead);
sbf.append("\r\n");
}
reader.close();
result = sbf.toString();
if (result != null) {
publishProgress(100);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
运行截图:
本文暂时更新到这里,以后有时间再继续更新
目标要实现的工具类有三个:UrlFileAsyNet(处理文件网络传输信息),UrlImageAsyNet(处理图片传输信息),UrlNormalAsyNet(处理JSON,XML,或String格式网络传输信息)。
以下是大神同学Dikaros写的完整AsyncTask工具包下载地址:https://github.com/Dikaros/AsyNet
QAQ(づ ̄ 3 ̄)づ求赞求关注!