Android学习——HttpURLConnection

HttpURLConnection

1.HTTP概述

如今,移动端APP渗透到各行各业,数量难以计数,几乎所有应用都会使用到网络,掌握Android网络编程是APP开发是核心技术,必备技术。这是因为移动设备的计算能力存储能力都是有限的。因此移动设备依赖网络计算、存储就成为了主要的方式,重要程度就不言而喻了。

Android完全支持JDK本身的TCP、UDP网络通信的API,也就是我们在JAVASE阶段讲解的网络编程,也叫Socket编程,Android也支持基于HTTP协议的URLConnection,并内置Apache HttpClient API来简化HTTP的操作。

当前最常用的网络编程技术,包括: URLConnection、Apache HttpClient、WebService、 Volley、android- async-http、WebView。

2.HTTP协议

HTTP是Hyper Text Transfer Protocol(超文本传输协议),它的发展史是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,最终发布了一系列法RFC/RFC1945定义了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定义了今天最普遍使用的一个版本——HTTP 1.1。

  1. 在TCP/IP协议栈中的位置
    HTTP协议通常承载于TCP协议之上,又是也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。默认端口号为80,HTTPS的端口号为443。
  2. HTTP的请求响应
    在这里插入图片描述
    这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。
    HTTP协议是一个无状态协议,同一个客户端的这次请求和上次请求是没有对应关系的。
  3. 工作流程
    一次HTTP操作称为一个事务,其工作过程可分为四步:
  • 首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作幵始。
  • 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
  • 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包栝服务器信息、实体信息和可能的内容。
  • 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。

如果在以上过程中的某-步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。

  1. 请求包示例
    HTTP请求包(GET?POST等请求方式)有三个部分构成,分别是:方法-URL-协议/版本,请求头,请求正文
    在这里插入图片描述
  2. 应答包示例
    和HTTP请求包相似,有三个部分构成,分别是:协议-状态代码-描述,应答头,应答正文
    在这里插入图片描述
    http的常见状态响应码
    200 OK:请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。
    400 Bad Request:语义有误,当前请求无法被服务器理解;请求参数有误。
    401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
    403 Forbidden:服务器已经理解请求,但是拒绝执行它。
    404 Not Found:请求失败,请求所希望得到的资源未被在服务器上发现。
    500 Internal Server Error:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。
    502 Bad Gateway:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。

3.检查网络连接状态

添加权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

判断是否有网络连接

public boolean isNetworkConnected(Context context){
    if (context!=null){
        ConnectivityManager connectivityManager= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
        if (networkInfo!=null){
            return networkInfo.isAvailable();
        }
    }
    return false;
}

在这里插入图片描述
判断WiFi网络是否可用

public boolean isWifiConnected(Context context){
    if (context!=null){
        ConnectivityManager connectivityManager= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo wiFiNetworkInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        if (wiFiNetworkInfo!=null){
            return wiFiNetworkInfo.isAvailable();
        }
    }
    return false;
}

判断网络连接的类型信息

public static int getConnectedType(Context context){
    if (context!=null){
        ConnectivityManager connectivityManager= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
        if (networkInfo!=null&&networkInfo.isAvailable()){
            return networkInfo.getType();
        }
    }
    return -1;
}

在这里插入图片描述

4.URL

URL:统一的资源定位符。Web上的每个资源都有唯一的地址,采用的就是URL格式
协议://服务器:端口号/路径/资源

5.显示一张网络图片到手机

添加权限

<uses-permission android:name="android.permission.INTERNET"/>

访问网络的操作必须在工作线程中操作

public void showNetImageClick(View view){
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                URL url = new URL("http://g.hiphotos.com/image/pic/item/dbb44aed2e738bd4f58b4e30a38b87d6277ff90d.jpg");
                InputStream inputStream=url.openStream();
                Bitmap bitmap=BitmapFactory.decodeStream(inputStream);
                Message msg=handler.obtainMessage(LOAD_SECCESS,bitmap);
                handler.sendMessage(msg);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

设置handler

private static class MyHandler extends Handler{
        private final WeakReference<Main2Activity> weakReference;
        public MyHandler(Main2Activity main2Activity){
            weakReference=new WeakReference<Main2Activity>(main2Activity);
        }
        @Override
        public void handleMessage(Message msg) {
            Main2Activity main2Activity=weakReference.get();
            if (main2Activity!=null){
                switch (msg.what){
                    case LOAD_SECCESS:
                        main2Activity.imageView.setImageBitmap((Bitmap) msg.obj);
                        break;
                }
            }
        }
    }

在这里插入图片描述

6.HttpURLConnection接口

HTTP通信中的POST和GET请求方式不同。GET把参数放在URL字符串的后面,传递给服务器。而POST方法的参数是放在HTTP请求中。因此,在编程之前,应当首先明确使用的请求方法,然后再根据所使用的方法选择相应的编程方式。
HttpURLConnection是继承于URLConnection类,二者都是抽象类。其对象主要通过URL的openConnection方法获得。

设置参数

urlConn.setDoOutput(true);//post情况下需要设置DoOutput为true,默认为false
urlConn.setDoInput(true);//设置是否从HttpURLConnection读入,默认情况下是true
urlConn.setRequestMethod(“POST”);
urlConn.setUseCache(false);//设置是否用缓存,post请求不能使用缓存

设置content-type

urlConn.setRequestPropery("content-type","application/x-www-form-urlencoded");
urlConn.setConnectTimeout(30000);//设置连接主机超时
urlConn.setReadTimeout(30000);//设置读取超时

模拟登陆客户端代码

package com.example.httpurlconnection;

import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.google.gson.Gson;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

public class Main3Activity extends AppCompatActivity {
    private static final int LOAD_SECCESS = 200;
    private static final int LOAD_ERROR = 400;
    private final Main3Activity.MyHandler handler=new Main3Activity.MyHandler(this);
    private TextView textView_info;
    private EditText editText_username,editText_password;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        textView_info=findViewById(R.id.info);
        editText_username=findViewById(R.id.editText_username);
        editText_password=findViewById(R.id.editText_pwd);
    }

    private static class MyHandler extends Handler {
        private final WeakReference<Main3Activity> weakReference;
        public MyHandler(Main3Activity main3Activity){
            weakReference=new WeakReference<Main3Activity>(main3Activity);
        }
        @Override
        public void handleMessage(Message msg) {
            Main3Activity main3Activity=weakReference.get();
            if (main3Activity!=null){
                switch (msg.what){
                    case LOAD_SECCESS:
                        String json= (String) msg.obj;
                        main3Activity.jsonToObject(json);
                        break;
                    case LOAD_ERROR:
                        main3Activity.textView_info.setText("登录失败,请检查用户名或者密码是否正确!");
                        break;
                }
            }
        }
    }

    //解析JSON为对象
    public void jsonToObject(String json){
        Gson gson=new Gson();
        JsonObject object=gson.fromJson(json,JsonObject.class);
        textView_info.setText(object.toString());
    }

    //登录功能
    public void loginClick(View view){
        final String username=editText_username.getText().toString();
        if (TextUtils.isEmpty(username)){
            Toast.makeText(this, "用户名不能为空!!!", Toast.LENGTH_SHORT).show();
            return;
        }
        final String password=editText_password.getText().toString();
        if (TextUtils.isEmpty(password)){
            Toast.makeText(this, "密码不能为空!!!", Toast.LENGTH_SHORT).show();
            return;
        }

        //启动登录工作线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                String path="http://10.0.2.2:8080/Android_NetServer/LoginServlet";
                try {
                    URL url=new URL(path);
                    //打开HTTP连接
                    HttpURLConnection conn= (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setDoInput(true);
                    conn.setDoOutput(true);
                    conn.setConnectTimeout(1000*30);//连接超时
                    conn.setReadTimeout(1000*30);//读取超时
                    conn.setUseCaches(false);
                    conn.setRequestProperty("content-type","application/x-www-form-urlencoded");
                    //对服务器端读取或写入数据(使用输入输出流)
                    //获取连接的输出流
                    DataOutputStream outputStream=new DataOutputStream(conn.getOutputStream());
                    outputStream.writeBytes("username="+ URLEncoder.encode("hello","UTF-8"));
                    outputStream.writeBytes("&password="+URLEncoder.encode("123"+"UTF-8"));
                    outputStream.flush();
                    outputStream.close();
                    //从服务器获取响应数据
                    BufferedReader br=new BufferedReader(new InputStreamReader(conn.getInputStream()));
                    String result=br.readLine();
                    System.out.println("result="+result);
                    br.close();
                    conn.disconnect();
                    Message msg=handler.obtainMessage(LOAD_SECCESS,result);
                    handler.sendMessage(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                    handler.sendEmptyMessage(LOAD_ERROR);
                }
            }
        }).start();
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/UUUUUltraman/article/details/89310871
今日推荐