Android访问网络的常用方式:Handler、AsyncTask简单例子(服务器端+Android端)

来源:互联网 发布:johnston murphy 淘宝 编辑:程序博客网 时间:2024/06/01 09:20

原文地址:http://blog.csdn.net/xuejingfu1/article/details/51915033

首先应该明白两点

1.Android不允许在主线程(对于android来说,主线程就是UI线程)中访问网络。

2.Android不允许在一个子线程中直接去更新主线程中的UI控件。

对于问题1,可能你会说,这还不好办吗?再开一个线程不就完了?是的,你很聪明,原理也很简单。

对于问题2,就需要用到线程间通信(IPC),Android很好的将其进行了封装,也就有了今天的Handler和AsyncTask。


适用情况:

AsyncTask是一个轻量级的后台异步任务类,简单、便捷。适合后台任务不太多的情况,因为每一个后台任务都要写成一个Class去继承AsyncTask,代码显得比较臃肿。否则就使用Handler吧,很强大,但对于新手来说较难掌握


使用方法:

AsyncTask定义了三种泛型类型 Params,Progress和Result

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。

最少要重写以下方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。(必须重写)
  • onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回(可以不重写,因为你可以用post(Runable r)来更新UI,但既然用了AsyncTask,直接重写这个方法多方便呢!)

有必要的话你还得重写以下这三个方法,但不是必须的:

  • onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
  • onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • onCancelled()             用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则

  • Task的实例必须在UI thread中创建;
  • execute方法必须在UI thread中调用;
  • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
  • 该task只能被执行一次,否则多次调用时将会出现异常;
Handler的使用要搭配线程(Thread)。具体使用方法,请看下面小例子。


服务器端代码:生成一个0到10之间的的随机数,并封装成JSON对象
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package com.test.servlet;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5.   
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.HttpServlet;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10.   
  11. public class TestServlet extends HttpServlet {  
  12.   
  13.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  14.             throws ServletException, IOException {  
  15.   
  16.         doPost(request, response);  
  17.     }  
  18.   
  19.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  20.             throws ServletException, IOException {  
  21.   
  22.         response.setContentType("text/html");  
  23.         PrintWriter out = response.getWriter();  
  24.           
  25.         out.println("{\"rand\":"+"\""+(int)(Math.random()*10)+"\""+"}");  
  26.         out.flush();  
  27.         out.close();  
  28.     }  
  29.   
  30. }  

这时先通过浏览器访问测试是否成功:

注意:8888是本人修改了tomcat的端口号,默认是8080哦,你们别学我^_^.

Android端:
布局文件就一个Textview用来显示数据:
[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     tools:context="xjtu.com.test.MainActivity">  
  7.   
  8.     <TextView  
  9.         android:id="@+id/tv"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="match_parent"  
  12.         android:textSize="50sp"  
  13.         android:gravity="center"/>  
  14. </LinearLayout>  

注意在Manifest文件中加入网络访问权限:
<uses-permission android:name="android.permission.INTERNET"/>
代码:

第一种方式AsyncTask:

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package xjtu.com.test;  
  2.   
  3. import android.os.AsyncTask;  
  4. import android.support.v7.app.AppCompatActivity;  
  5. import android.os.Bundle;  
  6. import android.widget.TextView;  
  7.   
  8. import org.json.JSONObject;  
  9.   
  10. import xjtu.com.utils.HttpUtils;  
  11.   
  12. public class MainActivity extends AppCompatActivity {  
  13.   
  14.     private TextView tv;  
  15.   
  16.     @Override  
  17.     protected void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.activity_main);  
  20.   
  21.        tv=(TextView)findViewById(R.id.tv);  
  22.         new GetData().execute();  
  23.     }  
  24.   
  25.     class GetData extends AsyncTask<Void,Void,String>{  
  26.   
  27.         @Override  
  28.         protected String doInBackground(Void... params) {  
  29.   
  30.             String json_str= HttpUtils.getJsonContent(HttpUtils.BaseUrl);  
  31.             String result="";  
  32.             try{  
  33.                 JSONObject js_obj=new JSONObject(json_str);  
  34.                 result=js_obj.getString("rand");  
  35.             }catch (Exception e){  
  36.                 e.printStackTrace();  
  37.             }  
  38.   
  39.             return result;  
  40.         }  
  41.   
  42.         @Override  
  43.         protected void onPostExecute(String s) {  
  44.             tv.setText(s);  
  45.         }  
  46.     }  
  47. }  
onPostExecute(String s)的参数s实际上是doInBackground方法的返回值result

结果截图:


第二种方式:Handler

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package xjtu.com.test;  
  2.   
  3. import android.os.Handler;  
  4. import android.os.Message;  
  5. import android.support.v7.app.AppCompatActivity;  
  6. import android.os.Bundle;  
  7. import android.widget.TextView;  
  8.   
  9. import org.json.JSONObject;  
  10.   
  11. import xjtu.com.utils.HttpUtils;  
  12.   
  13. public class MainActivity extends AppCompatActivity {  
  14.   
  15.     private TextView tv;  
  16.     private Thread thread;  
  17.     private Handler handler;  
  18.   
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.activity_main);  
  23.   
  24.         tv=(TextView)findViewById(R.id.tv);  
  25.           
  26.         //实例化一个handler在主线程中,等待接收来自子线程的Message  
  27.         handler=new Handler(){  
  28.             @Override  
  29.             public void handleMessage(Message msg) {  
  30.   
  31.                 if (msg.what == 0x123){//信息记号  
  32.                     Bundle bundle=msg.getData();  
  33.                     tv.setText(bundle.getString("text"));  
  34.                 }  
  35.             }  
  36.         };  
  37.     }  
  38.   
  39.     @Override  
  40.     protected void onResume() {  
  41.         super.onResume();  
  42.         thread=new Thread(new Runnable() {  
  43.             @Override  
  44.             public void run() {  
  45.   
  46.                 while(!Thread.currentThread().isInterrupted()) {  
  47.   
  48.                     String json_str = HttpUtils.getJsonContent(HttpUtils.BaseUrl);  
  49.                     String result = "";  
  50.                     try {  
  51.                         JSONObject js_obj = new JSONObject(json_str);  
  52.                         result = js_obj.getString("rand");  
  53.   
  54.                         //与主线程通信  
  55.                         Message message = new Message();  
  56.                         message.what = 0x123;  
  57.                         Bundle bundle = new Bundle();  
  58.                         bundle.putString("text", result);  
  59.                         message.setData(bundle);  
  60.                         handler.sendMessage(message);  
  61.                         //线程休眠1秒  
  62.                         Thread.sleep(1000);  
  63.   
  64.                     } catch (Exception e) {  
  65.                         e.printStackTrace();  
  66.                     }  
  67.   
  68.                 }  
  69.   
  70.             }  
  71.         });  
  72.   
  73.         //开启新线程  
  74.         thread.start();  
  75.     }  
  76.   
  77.     @Override  
  78.     protected void onStop() {  
  79.         super.onStop();  
  80.         //当前Activity终止时,阻塞线程  
  81.         thread.interrupt();  
  82.     }  
  83.       
  84. }  
这样得到的随机数每秒更新一次。


最后,以上代码中还用到了一个访问网络的封装类,代码如下:
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. package xjtu.com.utils;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.InputStream;  
  5. import java.net.HttpURLConnection;  
  6. import java.net.URL;  
  7.   
  8. public class HttpUtils {  
  9.   
  10.     public static String BaseUrl = "http://172.16.0.10:8888/Test/servlet/TestServlet";  
  11.   
  12.     public static String getJsonContent(String path) {  
  13.         try {  
  14.             URL url = new URL(path);  
  15.             HttpURLConnection connection = (HttpURLConnection) url.openConnection();  
  16.             connection.setConnectTimeout(3000);  
  17.             connection.setRequestMethod("GET");  
  18.             connection.setDoInput(true);  
  19.             int code = connection.getResponseCode();  
  20.             if (code == 200) {  
  21.                 return changeInputString(connection.getInputStream());  
  22.             }  
  23.         } catch (Exception e) {  
  24.             e.printStackTrace();  
  25.         }  
  26.         return "";  
  27.     }  
  28.   
  29.     private static String changeInputString(InputStream inputStream) {  
  30.   
  31.         String jsonString = "";  
  32.         ByteArrayOutputStream outPutStream = new ByteArrayOutputStream();  
  33.         byte[] data = new byte[1024];  
  34.         int len = 0;  
  35.         try {  
  36.             while ((len = inputStream.read(data)) != -1) {  
  37.                 outPutStream.write(data, 0, len);  
  38.             }  
  39.             jsonString = new String(outPutStream.toByteArray());  
  40.   
  41.         } catch (Exception e) {  
  42.             e.printStackTrace();  
  43.         }  
  44.         return jsonString;  
  45.     }  
  46. }  

0 0