上一篇的文章中,我给出了android和servlet之间数据的传递。实现了:android端数据打包--》发送给servlet端解析--》返回给android端
但还有一个很重要的内容,我以为很简单可以实现。结果纠结了两天才实现。即上述步骤的最后一步,就是【返回的数据显示到android上】
这个过程其实挺简单的,修改上一篇博文中2.1中的代码如下就可以了
public String sendJson(){ StringBuilder result = new StringBuilder(); String urlStr = "http://192.168.1.24:8080/servletTest/test"; HttpPost post = new HttpPost(urlStr); try{ JSONObject json = new JSONObject(); json.put("book_id", id); System.out.println("=============="+json.toString()); StringEntity se = new StringEntity(json.toString()); se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); post.setEntity(se); HttpClient httpClient = getHttpClient(); HttpResponse httpResponse = httpClient.execute(post); ///////////////////////////// int httpCode = httpResponse.getStatusLine().getStatusCode(); if(httpCode==HttpURLConnection.HTTP_OK && httpResponse != null){ HttpEntity entity = httpResponse.getEntity(); InputStream inputStream = entity.getContent(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader reader = new BufferedReader(inputStreamReader); String s; while((s=reader.readLine()) != null){ result.append(s); } reader.close(); JSONObject object = new JSONObject(result.toString()); String str = object.getString("book_list"); //detail1.setBookText(str); return str; } //////////////////////////// }catch(Exception exception){ exception.printStackTrace(); } return null; }
红色区域内的内容是新添加的,将返回的httpResponse中的内容提取出来,并返回一个str字符串。
到目前为止,都没有什么问题。但是当我们试图将返回的str字符串用于更新UI内容的时候,android报错,说UI内容的修改只能在创建UI的线程中才能修改,也就是说只能在主线程中修改;而不能在子线程中修改。
这个时候就出现了一个矛盾体。访问服务器的操作必须要在子线程中,因为它是一个耗时操作,会降低UI线程的性能;而UI的更新操作必须在UI线程中,子线程不允许修改UI。这个时候,我们需要的就是——线程间的通讯。
是的,当子线程获取了servlet返回的数据后,将数据通过线程间通讯的方式发送给主线程。主线程收到这个消息后,再更新UI。就是这样一个过程。
这个时候就不再涉及到servlet端的代码了,因为servlet已经把数据都返回回来。所以下面我只给出android端的代码。
/**** android code ****/
package com.example.douban250; @SuppressLint("HandlerLeak") public class BookDetailsActivity extends ActionBarActivity{ private BookDetail detail1; private ImageButton backButton; private String responseMsg = ""; int id; private Handler mMainHandler, mChildHandler; protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.book_detail_main); detail1 = (BookDetail)this.findViewById(R.id.book_detail); Intent intent = getIntent(); id = intent.getIntExtra("id", -1); mMainHandler = new Handler(){ public void handleMessage(Message msg){ //接收子线程的消息 detail1.setBookText((String)msg.obj); System.out.println("==========main thread get the message:"+msg.obj); System.out.println("Finally, the message is :"+msg.obj); } }; QueryThread thread = new QueryThread(); thread.start(); while(mChildHandler == null){ } if(mChildHandler != null){ //发送消息给子线程 Message childMsg = mChildHandler.obtainMessage(); childMsg.obj = mMainHandler.getLooper().getThread().getName(); System.out.println("==========send message to mChild: "+childMsg.obj); mChildHandler.sendMessage(childMsg); } } public void onDestroy(){ super.onDestroy(); mChildHandler.getLooper().quit(); } public String getBookDetails(){ //与servlet交互的实现代码 StringBuilder result = new StringBuilder(); String urlStr = "http://192.168.1.21:8080/servletTest/test"; HttpPost post = new HttpPost(urlStr); try{ //发送request JSONObject json = new JSONObject(); json.put("book_id", id); System.out.println("=============="+json.toString()); StringEntity se = new StringEntity(json.toString()); se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); post.setEntity(se); HttpClient httpClient = getHttpClient(); HttpResponse httpResponse = httpClient.execute(post); //接收到response并处理 int httpCode = httpResponse.getStatusLine().getStatusCode(); if(httpCode==HttpURLConnection.HTTP_OK && httpResponse != null){ HttpEntity entity = httpResponse.getEntity(); InputStream inputStream = entity.getContent(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader reader = new BufferedReader(inputStreamReader); String s; while((s=reader.readLine()) != null){ result.append(s); } reader.close(); JSONObject object = new JSONObject(result.toString()); String str = object.getString("book_list"); //detail1.setBookText(str); //得到最终返回的结果 return str; } }catch(Exception exception){ exception.printStackTrace(); } return null; } public HttpClient getHttpClient(){ BasicHttpParams httpParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParams, 5*1000); HttpConnectionParams.setSoTimeout(httpParams, 10*1000); HttpClient client = new DefaultHttpClient(httpParams); return client; } class QueryThread extends Thread{ public void run(){ //初始化消息循环队列,需要在Handler创建之前 Looper.prepare(); mChildHandler = new Handler(){ public void handleMessage(Message msg){ //访问网络等工作 String book_titleString = getBookDetails(); System.out.println("================book_title from servlet is "+book_titleString); Message toMain = mMainHandler.obtainMessage(); toMain.obj = book_titleString; //向主线程当前线程的Looper对发送message System.out.println("================send message to main thread: "+book_titleString); mMainHandler.sendMessage(toMain); } }; //启动子线程消息循环队列 Looper.loop(); System.out.println("================json is done!"); } } }
过程就是这样的,onCreate方法中的以下这段代码,我也不是太懂是什么意思。但是我理解的就是讲mChildHandler注册到消息队列中去。这样的话mMainHandler就知道有这么一个消息了。
if(mChildHandler != null){ //发送消息给子线程 Message childMsg = mChildHandler.obtainMessage(); childMsg.obj = mMainHandler.getLooper().getThread().getName(); System.out.println("==========send message to mChild: "+childMsg.obj); mChildHandler.sendMessage(childMsg); }
然后QueryThread中的下面这段代码就是,就是将网络访问中的返回值——book_titleString当做消息的内容,传递给mMainHandler。
mChildHandler = new Handler(){ public void handleMessage(Message msg){ //访问网络等工作 String book_titleString = getBookDetails(); System.out.println("================book_title from servlet is "+book_titleString); Message toMain = mMainHandler.obtainMessage(); toMain.obj = book_titleString; //向主线程当前线程的Looper对发送message System.out.println("================send message to main thread: "+book_titleString); mMainHandler.sendMessage(toMain); } };
最后mMainHandler作为主线程,接收到这个消息,并将其中的信息提取出来,更新UI。下面标红的代码就是我封装的一个修改UI的代码。跟textView.setText((String)msg.obj)是一个意思。
mMainHandler = new Handler(){ public void handleMessage(Message msg){ //接收子线程的消息 detail1.setBookText((String)msg.obj); System.out.println("==========main thread get the message:"+msg.obj); System.out.println("Finally, the message is :"+msg.obj); } };
Bon Appetite~