关于Android4.0不能再线程下改变UI的解决方案

来源:互联网 发布:梦幻西游mac无法更新 编辑:程序博客网 时间:2024/05/21 10:20

前几天,参加上海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打印机完成了很多优秀的作品,很遗憾的和大奖擦身而过。

0 0
原创粉丝点击