前几天,参加上海hack马拉松比赛,合作完成了一个简单的住房android手机应用,其中,就遇到了线程与ui变化的冲突,
队友Android的刚入门,于是,我负责了Android的网络和数据传输部分,队友设计布局和界面。
问题还原:
用户按下按钮的时候,httpclient根据需要发起json数据请求连接到php后端,后端收到数据进行处理后,返回给Android的http线程,然后Android端口的httpclient线程接受数据并对数据进行处理,并最终调整ui界面的状态。
但是,在click监听事件下,直接调用httpclient会导致报错
问题原因:
button的click事件的监听状态下http线程不被允许改变ui界面。
解决方案:
新建一个线程,然后在线程下运行httpclient,将接受到的数据使用bundle进行包装,放入message对象中,传输给相应的handler进行处理
代码:
根据上面描述,得到 rcp类和ecpProxy类,rcpProxy是继承线程的,调用实际的rcp进行http连接和response的处理。
实例代码:
public class RPCProxy extends Thread{
private RPC rpc = null;
public RPCProxy(RPC rpc) {
this.rpc = rpc;
}
@Override
public void run() {
// TODO Auto-generated method stub
rpc.getResponse();
}
}
public class RPC {
private List<NameValuePair> pairList = null;
private String base_Url = "";
private Handler handler = null;
private int choice = 0;
// private JSONObject object = null;
public RPC(List<NameValuePair> pairList_param, String base_url_param,
Handler handler_param) {
base_Url = base_url_param;
pairList = pairList_param;
this.handler = handler_param;
// this.object = object;
}
public RPC(List<NameValuePair> pairList_param, String base_url_param,
Handler handler_param,int choice) {
base_Url = base_url_param;
pairList = pairList_param;
this.handler = handler_param;
this.choice = choice;
// this.object = object;
}
public void getResponse() {
// assert(pairList!=null);
try {
if(pairList!=null){
HttpEntity requestHttpEntity = new UrlEncodedFormEntity(
this.pairList, HTTP.UTF_8);
HttpPost httpPost = new HttpPost(this.base_Url);
httpPost.setEntity(requestHttpEntity);
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(httpPost);
// assert(response!=null);
//调用response的处理,这里就不做response的等待时延的问题了
dealResponse(response);
}else{
Message message = new Message();
message.what=1;
handler.sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
// 暂时不做处理
}
}
// public abstract void dealResponse(HttpResponse response);
public void dealResponse(HttpResponse response) {
// TODO Auto-generated method stub
if (null == response) {
return;
}
HttpEntity httpEntity = response.getEntity();
try {
String strResult = EntityUtils.toString(httpEntity);
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("result", strResult);
message.setData(bundle);
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
}
使用MainActivity进行测试
先定义一个handler消息处理对象
//获取收藏的handler,这里传回来的数据是json的数组,进行处理
private Handler handler1_get_collection = new Handler() {
public void handleMessage(android.os.Message msg) {
Bundle res = msg.getData();
try {
JSONArray array = new JSONArray(res.getString("result"));
JSONObject obj = array.getJSONObject(0);
// text.setText("Hello"+obj);
text.setText("Coming here->"+obj.getString("house_id")+"->"+obj.getString("house_infomation")+
"->"+obj.getString("house_price")+"->"+obj.getString("house_address")+
"->"+obj.getString("owner_id"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// text.setText("Coming here"+res.getString("result"));
super.handleMessage(msg);
}
};
//收房租,这里传回来的数据是json的对象,进行处理
private Handler handler1_get_money = new Handler() {
public void handleMessage(android.os.Message msg) {
Bundle res = msg.getData();
//登陆的判断
if(res.getString("feeCharging").equals("false")){
text.setText("收房租失败啊"+res.getString("feeCharging"));
}else{
text.setText("收房租成功啊"+res.getString("feeCharging"));
}
super.handleMessage(msg);
}
};
private Handler handler1_get_money = new Handler() {
public void handleMessage(android.os.Message msg) {
Bundle res = msg.getData();
JSONObject array = new JSONAObject(res.getString("result"));
if(res.getString("feeCharging").equals("false")){
text.setText("收房租失败啊"+res.getString("feeCharging"));
}else{
text.setText("收房租成功啊"+res.getString("feeCharging"));
}
super.handleMessage(msg);
}
};
按钮绑定事件:
Button button = (Button) findViewById(R.id.send);
button.setOnClickListener(new OnClickListener() {
NameValuePair pair1 = new BasicNameValuePair("user_id","2"); //根据存储的字段
List<NameValuePair> pairList = new ArrayList<NameValuePair>();
pairList.add(pair1);
final RPC rpc = new RPC(pairList,"http://hacksh.sinaapp.com/getCollectInfo.php",handler1_get_collection); //第一个参数是键值对列表,传给后台的参数,第二个是后台的url地址,第三个相应的handler处理程序,
new RPCProxy(rpc).start(); //通过rpcProxy代理实现rpc的功能
}
只要通过改变rpc的url和键值对列表的信息,并给出相应的handler处理对象,就可以了,其他的都不要变化,很好的分离了网络后台和界面前台
最后,说说这次比赛的感想吧。我们小组四个人,通过一天一夜的操作,完成了这个作品,劳动强度很大,通过重构代码,开发速度大大提升,整体架构比较常规php+mysql+json+Android+httpclient完成,整体很nice,但是别人的作品更加优秀,使用leap motion、3D打印机完成了很多优秀的作品,很遗憾的和大奖擦身而过。