http请求是耗时操作,如果把它放到主线程上,会造成UI线程阻塞,android在API8以后不允许开发者将网络耗时操作放到主线程上进行.对于开子线程进行http请求,从服务器返回的数据,需要主线程来处理,并更新UI,子线程不能更新UI,所以这里涉及到子线程和主线程的通信.android提供handler消息处理机制来实现线程通信,子线程将网络返回结果通过发送消息的形式通知主线程,主线程接收消息,处理数据,并进行UI操作,这样就实现了整个客户端向服务器发送请求并接收请求,处理请求的过程.对于子线程设计,这里建议采取线程模板设计的方式.步骤如下
首先,自定义模板线程,继承线程类,把它设置成抽象类,作为具体线程的父类
public abstract class BaseThread extends Thread {
protected String requestURL;
protected Map resultMap;
protected Map requestParams;
protected List resultList;
protected Handler mHandler;
protected Message msg;
protected String stateId;
/**
* handler是关于主线程的交互类
* stateId是与主线程的message的标识号
*
* @param mHandler
* @param stateId
*/
stateID用以作为message的标签
public BaseThread(Handler mHandler, String stateId) {
this.mHandler = mHandler;
this.stateId = stateId;
}
其次,设计一个方法,用以初始化http具体请求的url,和请求参数
/**
* 设置POST表单的参数和请求主机的位置
*
* @param requestURL
* @param requestParams
*/
public void setRequestPrepare(String requestURL, Map requestParams) {
this.requestURL = requestURL;
this.requestParams = requestParams;
}
然后,设计一个方法,用来获取从服务器得到的字符串经过处理后的Map表,此方法为主线程服务.
/**
* 获取返回结果,结果为Map形式的
*
* @return
*/
public Map getResultMap() {
if (this.resultMap != null) {
return (this.resultMap);
} else {
this.resultMap = new HashMap();
return (this.resultMap);
}
}
设计一个方法,用以判断请求成功与否
/**
* 根据httpUtils类返回的字符串来确定请求成功与否
* @param str
* @return
*/
protected boolean dealRequestState(String str) {
if (str != null) {
if (str.equals("paramsException")) {
return (false);
} else if (str.equals("singleTonException")) {
return (false);
} else if (str.equals("InterNetException")) {
return (false);
} else if (str.equals("switchException")) {
return (false);
} else {
return (true);
}
} else {
Log.i("lzw","null");
return (false);
}
}
随后,设计一个方法,用来存放网络状态的消息
/**
* 通知主线程加载的状态
*
* @param key
* @param state
*/
protected void setLoadState(String key, int state) {
this.msg = new Message();
Bundle bd = new Bundle();
bd.putInt(key, state);
this.msg.setData(bd);
}
该方法用以检查请求参数
protected void checkRequestMap()
{
Iterator it=this.requestParams.entrySet().iterator();
while(it.hasNext())
{
Map.Entry<String,String> entry=(Map.Entry<String,String>)it.next();
Log.i("lzw",entry.getKey());
Log.i("lzw",entry.getValue());
}
}
最后,来实现run方法
/**
* 主要的线程体方法,先是请求服务器,
* 将服务器的返回的结果(字符)交给子类的实例化的方法来
*/
public void run() {
this.checkRequestMap();
// Log.i("lzw","URL="+this.requestURL);
try {
//上一篇文章用到的用以实现发送http请求httputils
//实现发送请求方法,请求参数和路径由主线程通过调用setRequestPrepare方法初始化
//HttpUtils执行requestHttpSever方法,得到返回字符串存放在变量responseStr中
String responseStr =
HttpUtils.requestHttpServer(this.requestURL, this.requestParams,
ComParameter.ENCODE_UTF_8, ComParameter.ENCODE_UTF_8);
//通过调用dealRequestState函数来判断服务器连接状态,传入参数为服务器返回字符串
if (!this.dealRequestState(responseStr)) {
//没有返回成功,保存错误消息
this.setLoadState(this.stateId, ComParameter.STATE_ERROR);
//将错误消息发送给主线程,交给主线程handler处理
this.mHandler.sendMessage(this.msg);
return;
}
//若果返回的字符串正常,处理返回字符,以map的形式存放,这个方法为抽象方法,放在子类中进行
this.dealReponseString(responseStr);
//告诉主线程,返回成功
this.setLoadState(this.stateId, ComParameter.STATE_RIGHT);
this.mHandler.sendMessage(this.msg);
} catch (Exception e) {
this.setLoadState(this.stateId, ComParameter.STATE_ERROR);
this.mHandler.sendMessage(this.msg);
e.printStackTrace();
}
}
将处理返回字符串的方法,作为抽象方法,因为不同的请求返回的字符串可能不一样,放在子类处理
protected abstract void dealReponseString(String responseString) throws Exception;
下面写一个子类用来继承线程模板,处理返回字符串的示例
public class FirstLoginRequestThread extends BaseThread {
public FirstLoginRequestThread(Handler mHandler, String stateId) {
super(mHandler, stateId);
}
protected void dealReponseString(String responseString) throws Exception{
//这里的resultMap是父类属性,这个方法用来处理服务器返回字符串,向父类的Map添加内容,为主线程得到返回参数服务
this.resultMap = new HashMap<String, String>();
String tmpArrStr[] = responseString.split(":");
if (tmpArrStr[1].equals("login")) {
String tmpArrStr1[]=tmpArrStr[2].split("[+]");
this.resultMap.put(tmpArrStr[0], tmpArrStr[1]);
this.resultMap.put("type", tmpArrStr1[0]);
this.resultMap.put("dataBaseId", tmpArrStr[3]);
} else if (tmpArrStr[1].equals("unlogin")) {
this.resultMap.put(tmpArrStr[0], tmpArrStr[1]);
this.resultMap.put("failReason", tmpArrStr[2]);
}
Log.i("lzw",responseString);
}
}