Android学习五 网络编程与handler消息机制

来源:互联网 发布:淘宝投诉卖家后没用啊 编辑:程序博客网 时间:2024/05/22 11:38

      Android中许多应用需要从网络上获取内容,而如何从网络上获取内容,这就需要用到网络编程的知识。下面是Android中关于网络编程的一些知识。

一、使用httpURLConnection对象访问网络

    使用UrlConnection请求一个url地址获取内容的一般步骤如下:

//1.创建一个Url对象
       URL url = new URL(url_str);

//2.获取一个UrlConnection对象
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//3.为UrlConnection对象设置一些请求的参数,请求方式,连接的超时时间
        connection.setRequestMethod("GET");//设置请求方式
        connection.setConnectTimeout(1000*10);//设置超时时间

//4.在获取url请求的数据前需要判断响应码,200 :成功,206:访问部分数据成功   300:跳转或重定向  400:错误 500:服务器异常
        int code = connection.getResponseCode();

//5.获取有效数据,并将获取的流数据解析成String
         InputStream inputStream = connection.getInputStream();
         String result = StreamUtils.streamToString(inputStream);

注意访问网络需要设置android.permission.INTERNET  这个权限。

       如果直接在主线程中做网络请求的话,可能会ANR:application not response 应用无响应的错误,这是因为Android中的耗时操作(请求网络,大文件的拷贝,数据库的操作等)需要在子线程中去做,但是在子线程中不能够更新控件(如Toast的展示及其他界面的修改操作)。这是可能就会产生问题,当即需要请求网络有需要更新UI时该怎么办呢?

这是后就需要handler了。

二、handler的使用

     handler可以在子线程和主线程之间传递消息,当子线程中需要更新UI时,只需要把要更新的内容用handler传递到主线程中,在主线程中更新即可。下面来看一下handler的用法。

        1.主线程中创建一个Handler
        private Handler handler = new Handler(){
                public void handleMessage(android.os.Message msg) {
                };
        };
        2.重写handler的handlermessage方法
        3.子线程中创建一个Message对象,将获取的数据绑定给msg
                Message msg = new Message();
                //另一种方式:Message msg = Messge.obtain;
                msg.obj = result;
        4.主线程中的handler对象在子线程中将message发送给主线程
                handler.sendMessage(msg);
        5.主线程中handlermessage方法接受子线程发来的数据,就可以做更新UI的操作。

下面来看一段示例代码:

 private EditText et_url;    private TextView tv_source;    private Context mContext;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mContext = this;        //一、获取控件        et_url = (EditText) findViewById(R.id.et_url);        Button bt_looksource = (Button) findViewById(R.id.bt_looksource);        tv_source = (TextView) findViewById(R.id.tv_source);        //二、绑定点击事件        bt_looksource.setOnClickListener(this);        System.out.println("oncreate方法线程:"+Thread.currentThread().getName());    }    //使用handler在子线程和主线程之间传递消息的步骤    //a.在主线程中创建一个handler对象    private Handler handler = new Handler(){        //b重写handler对象中的handlerMessage方法,用来接收子线程中发来的消息        @Override        public void handleMessage(Message msg) {            //e.接收子线程发来的消息,处理消息            String result = (String)msg.obj;            System.out.println("获取到信息");            //五、更新UI            tv_source.setText(result);        }    };    @Override    public void onClick(View view) {        //ctrl+alt+t快速添加try catch块        try {            //三、获取输入的url地址            final String url_str = et_url.getText().toString().trim();            if(TextUtils.isEmpty(url_str)){                //???                Toast.makeText(mContext,"url不能为空",Toast.LENGTH_SHORT).show();                return ;            }            System.out.println("onclick方法线程:"+Thread.currentThread().getName());            //四、创建一个子线程做网络请求            new Thread(new Runnable() {                @Override                public void run() {                    try {                        System.out.println("oclick方法runnable线程:"+Thread.currentThread().getName());                        //使用UrlConnection请求一个url地址获取内容                        //1.根据url地址创建一个URL对象                        URL url = new URL(url_str);                        //2.获取一个URLConnection对象                        HttpURLConnection connection = (HttpURLConnection) url.openConnection();                        connection.setRequestMethod("GET");                        connection.setConnectTimeout(1000*10);                        System.out.println("第一次请求的请求码"+connection.getResponseCode());                        //3.获取头部信息,获取到重定向后的地址(为了解决返回码为302的问题)                        String location = connection.getHeaderField("Location");                        System.out.println("location "+location+"");                        //4.为URLConnection设置请求参数(请求方式,连接的超时时间等)                        url  = new URL(location);                        connection = (HttpURLConnection) url.openConnection();                        connection.setRequestMethod("GET");                        connection.setConnectTimeout(1000*10);                        //4.判断响应码                        int code = connection.getResponseCode();                        System.out.println(code);                        if(code == 200){                            //5.获取有效数据,并将数据解析为字符串                            InputStream inputStream = connection.getInputStream();                            String result = StreamUtils.streamToString(inputStream);                            //c.子线程中创建一个Message对象,用于将子线程中的数传递给主线程                            Message message = new Message();                            message.obj = result;                            //d.使用handler将数据从子线程传递到主线程                            handler.sendMessage(message);                        }else{                            System.out.println("请求url失败");                        }                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }).start();        } catch (Exception e) {            e.printStackTrace();        }    }
public class StreamUtils {    public static String streamToString(InputStream in){        String result = "";        try {            ByteArrayOutputStream out = new ByteArrayOutputStream();            byte[] buffer = new byte[1024];            int length = 0;            while((length = in.read(buffer)) != -1){                out.write(buffer,0,length);                out.flush();            }            result = out.toString();            out.close();        } catch (IOException e) {            e.printStackTrace();        }        return result;    }}
在子线程中更新UI的其他集中方法:

        1.使用activity的runOnUiThread方法更新ui,无论当前线程是否是主线程,都将在主线程执行。注意runOnUiThread不能在静态类中使用
                runOnUiThread(new Runnable() {              
                    @Override
                    public void run() {
                        tv_simple.setText("我被更新了");
                    }
                });
        2.使用handler直接post到主线程,handler需要在主线程创建
                    //延迟多少毫米执行runnable。
                    mHandler.postDelayed(new Runnable() {      
                    @Override
                    public void run() {
                        tv_simple.setText("我被更新了");
                    }
                }, 1000*5);

还有需要注意的是不能在子线程中更新UI并不是绝对的。以下集中情形可以在子线程中更新UI:SurfaceView :多媒体视频播放 ,可以在子线程中更新UI; Progress(进度)相关的控件:也是可以在子线程中更新Ui;审计机制:activity完全显示的时候审计机制才会去检测子线程有没有更新Ui。

三、get和post请求

     在请求网络时需要设置请求方式,常用的请求方式有两种post和get。get的请求内容是跟在URL地址后面(不安全且大小有限制但是简单),post的请求内容是放在请求体当中(大小无限制,安全,但是繁琐)。使用post请求相比get请求还需要设置一下内容:

请求头的设置(不是必需的)
            openConnection.setRequestProperty("Content-Length", body.length()+"");
            openConnection.setRequestProperty("Cache-Control", "max-age=0");
            openConnection.setRequestProperty("Origin", "http://192.168.13.83:8080");
请求内容的设置(必需)
             //设置UrlConnection可以写请求的内容
            openConnection.setDoOutput(true);
            //获取一个outputstream,并将内容写入该流
            openConnection.getOutputStream().write(body.getBytes());

使用post请求方式时还要注意编码要一致,否则可能产生乱码。可以使用URLEncode对数据进行编码。

四、用httpClient做网络请求

       直接上代码,get方式:

try{String path = "http://192.168.13.83:8080/itheima74/servlet/LoginServlet?username="+URLEncoder.encode(username,"utf-8")+"&pwd="+URLEncoder.encode(password,"utf-8");//1.创建一个httpClient对象HttpClient httpclient = new DefaultHttpClient();//2.设置请求的方式HttpGet httpget = new HttpGet(path);//3.执行一个http请求HttpResponse response = httpclient.execute(httpget);//4.获取请求的状态码,StatusLine statusLine = response.getStatusLine();int code = statusLine.getStatusCode();//5.判断状态码后获取内容if(code == 200){HttpEntity entity = response.getEntity();//获取实体内容,中封装的有http请求返回的流信息InputStream inputStream = entity.getContent();//将流信息转换成字符串String result = StreamUtils.streamToString(inputStream);Message msg = Message.obtain();msg.what = 1;msg.obj = result;handler.sendMessage(msg);}}catch (Exception e) {e.printStackTrace();}
post方式:

String path = "http://192.168.13.83:8080/itheima74/servlet/LoginServlet";AsyncHttpClient asyncHttpClient = new AsyncHttpClient();RequestParams params = new RequestParams();params.put("username", username);params.put("pwd", password);//url:   parmas:请求时携带的参数信息   responseHandler:是一个匿名内部类接受成功过失败asyncHttpClient.post(path, params, new AsyncHttpResponseHandler() {@Overridepublic void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {//statusCode:状态码    headers:头信息  responseBody:返回的内容,返回的实体//判断状态码if(statusCode == 200){//获取结果try {String result = new String(responseBody,"utf-8");Toast.makeText(context, result, 0).show();} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}@Overridepublic void onFailure(int statusCode, Header[] headers,byte[] responseBody, Throwable error) {}});


 


0 0
原创粉丝点击