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

匿名 (未验证) 提交于 2019-12-03 00:43:02

首先应该明白两点:

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对象

  
  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用来显示数据:

  
  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:

 

  
  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

 

  
  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. }

这样得到的随机数每秒更新一次。

 

 

最后,以上代码中还用到了一个访问网络的封装类,代码如下:

  
  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. }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!