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

首先应该明白两点

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对象
package com.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		
		out.println("{\"rand\":"+"\""+(int)(Math.random()*10)+"\""+"}");
		out.flush();
		out.close();
	}

}

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

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

Android端:
布局文件就一个Textview用来显示数据:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="xjtu.com.test.MainActivity">

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="50sp"
        android:gravity="center"/>
</LinearLayout>

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

第一种方式AsyncTask:

package xjtu.com.test;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import org.json.JSONObject;

import xjtu.com.utils.HttpUtils;

public class MainActivity extends AppCompatActivity {

    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       tv=(TextView)findViewById(R.id.tv);
        new GetData().execute();
    }

    class GetData extends AsyncTask<Void,Void,String>{

        @Override
        protected String doInBackground(Void... params) {

            String json_str= HttpUtils.getJsonContent(HttpUtils.BaseUrl);
            String result="";
            try{
                JSONObject js_obj=new JSONObject(json_str);
                result=js_obj.getString("rand");
            }catch (Exception e){
                e.printStackTrace();
            }

            return result;
        }

        @Override
        protected void onPostExecute(String s) {
            tv.setText(s);
        }
    }
}
onPostExecute(String s)的参数s实际上是doInBackground方法的返回值result

结果截图:


第二种方式:Handler

package xjtu.com.test;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import org.json.JSONObject;

import xjtu.com.utils.HttpUtils;

public class MainActivity extends AppCompatActivity {

    private TextView tv;
    private Thread thread;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv=(TextView)findViewById(R.id.tv);
        
        //实例化一个handler在主线程中,等待接收来自子线程的Message
        handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {

                if (msg.what == 0x123){//信息记号
                    Bundle bundle=msg.getData();
                    tv.setText(bundle.getString("text"));
                }
            }
        };
    }

    @Override
    protected void onResume() {
        super.onResume();
        thread=new Thread(new Runnable() {
            @Override
            public void run() {

                while(!Thread.currentThread().isInterrupted()) {

                    String json_str = HttpUtils.getJsonContent(HttpUtils.BaseUrl);
                    String result = "";
                    try {
                        JSONObject js_obj = new JSONObject(json_str);
                        result = js_obj.getString("rand");

                        //与主线程通信
                        Message message = new Message();
                        message.what = 0x123;
                        Bundle bundle = new Bundle();
                        bundle.putString("text", result);
                        message.setData(bundle);
                        handler.sendMessage(message);
                        //线程休眠1秒
                        Thread.sleep(1000);

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

            }
        });

        //开启新线程
        thread.start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        //当前Activity终止时,阻塞线程
        thread.interrupt();
    }
    
}
这样得到的随机数每秒更新一次。


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

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpUtils {

    public static String BaseUrl = "http://172.16.0.10:8888/Test/servlet/TestServlet";

    public static String getJsonContent(String path) {
        try {
            URL url = new URL(path);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(3000);
            connection.setRequestMethod("GET");
            connection.setDoInput(true);
            int code = connection.getResponseCode();
            if (code == 200) {
                return changeInputString(connection.getInputStream());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    private static String changeInputString(InputStream inputStream) {

        String jsonString = "";
        ByteArrayOutputStream outPutStream = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        int len = 0;
        try {
            while ((len = inputStream.read(data)) != -1) {
                outPutStream.write(data, 0, len);
            }
            jsonString = new String(outPutStream.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return jsonString;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值