学习笔记:Android中使用网络技术的方法(webview、httpurlconnection、okhttp)
目录
一、使用HttpUrlConnection访问网络
1、发送GET请求
tips: 如何处理302重定向
2、发送POST请求
二、OkHttp的使用方法
三、WebView的使用方法
一、使用HttpUrlConnection访问网络
在Android 6.0以前,Android上发送HTTP请求一般有两种方式,HttpUrlConnection和HttpClient。HttpClient是Apache的开源库,存在API数量过多、扩展困难等缺点,在Android6.0系统中,将HttpClient的功能完全移除了。官方建议使用HttpUrlConnection来进行网络请求。
1、发送GET请求
/* 使用HttpUrlConnection发送GET请求 */ public static void sendHttpGetRequest(final String address){ new Thread(new Runnable() { @Override public void run() { URL url = null;//请求的url地址 HttpURLConnection conn = null; InputStream is = null; ByteArrayOutputStream baos = null; String requestHeader = null;//请求头 String requestBody = null;//请求体 String responseHeader = null;//响应头 String responseBody = null;//响应体 try { //创建一个URL对象 url = new URL(address); //打开一个HttpUrlConnection连接 conn = (HttpURLConnection)url.openConnection(); //设置GET、POST请求方式,默认使用GET发送请求 conn.setRequestMethod("GET"); //设置连接超时时间 conn.setConnectTimeout(5000); //设置从服务器读取数据超时时间 conn.setReadTimeout(5000); //设置是否使用缓存,默认true conn.setUseCaches(true); //设置从服务端读取结果流,默认true conn.setDoInput(true); //用来设置请求头 conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("TestDemo", "GET"); //在对各种参数配置完成后,通过调用connect方法建立TCP连接,但是并未真正获取数据 //connect()方法不必主动调用,当调用getInputStream()方法时内部也会自动调用connect方法 conn.connect(); if(conn.getResponseCode() == 200){ //调用getInputStream方法后,服务端才会收到请求,并阻塞式地接收服务端返回的数据 is = conn.getInputStream(); baos = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len = 0; while((len = is.read(bytes)) != -1){ baos.write(bytes, 0, len); } requestBody = baos.toString(); Log.d(TAG, "run: response " + requestBody); }else if(conn.getResponseCode() == 302){ //处理重定向,这里只是一个简单的例子,不是标准写法 String location = conn.getHeaderField("Location"); url = new URL(location); //打开一个HttpUrlConnection连接 conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setUseCaches(true); conn.connect(); } } catch (Exception e) { e.printStackTrace(); }finally { try { if (baos != null){ baos.close(); } if(is != null){ is.close(); } if(conn != null){ conn.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } }).start(); }
tips: 如何处理302重定向
1、网络请求属于耗时操作,不可以在主线程内进行,需要单独起一个线程进行网络请求操作;
2、HttpUrlConnection有两个方法来设置是否自动处理重定向setFollowRedirects()和setInstanceFollowRedirects(),但我设置后访问http://www.baidu.com,并没有自动重定向,还会返回302的错误码,手动处理后,可以获取response header里的Location,是重定向后的url。而OkHttp可以自动处理重定向,okhttp的重定向默认是开启的,可以手动设置为关闭。
2、发送POST请求
/* * 使用HttpUrlConnection发送POST请求 * */ public static void sendHttpPostRequest(final String address){ new Thread(new Runnable() { @Override public void run() { URL url = null; HttpURLConnection conn = null; DataOutputStream dos = null; InputStream is = null; ByteArrayOutputStream baos = null; String requestHeader = null;//请求头 String requestBody = null;//请求体 String responseHeader = null;//响应头 String responseBody = null;//响应体 try { //创建一个URL对象 url = new URL(address); //打开一个HttpUrlConnection连接 conn = (HttpURLConnection)url.openConnection(); //设置请求方式为POST,必须设置,默认GET conn.setRequestMethod("POST"); //设置允许输出,POST请求必须设置,默认false conn.setDoOutput(true); //设置请求默认输入,默认true conn.setDoInput(true); //设置请求头 conn.setRequestProperty("TestDemo", "POST"); //设置连接超时时间 conn.setConnectTimeout(5000); //设置从服务器读取数据超时时间 conn.setReadTimeout(5000); //设置本次连接是否自动处理重定向 conn.setInstanceFollowRedirects(true); //开始连接 conn.connect(); //发送请求的POST参数,键值对形式 dos = new DataOutputStream(conn.getOutputStream()); dos.writeBytes("username=prance&password=123456"); dos.flush(); dos.close(); if(conn.getResponseCode() == 200){ is = conn.getInputStream(); baos = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len = 0; while((len = is.read(bytes))!=-1){ baos.write(bytes, 0 , len); } responseBody = baos.toString(); Log.d(TAG, "run: response" + responseBody); } } catch (Exception e) { e.printStackTrace(); }finally { try { if (baos != null){ baos.close(); } if(is != null){ is.close(); } if(conn != null){ conn.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } }).start(); }
二、OkHttp的使用方法
1、添加OkHttp库的依赖
在app/build.gradle文件中,dependencies闭包中加入依赖:
dependencies { ...... implementation 'com.squareup.okhttp3:okhttp:3.12.1'}
其他引入方式,见github上okhttp库的说明:https://github.com/square/okhttp
2、使用方法
(1)Get请求
/*发送HTTP Get请求 * 参数: * address:请求的url地址 * */ public static void sendOkHttpRequest(final String address){ new Thread(new Runnable() { @Override public void run() { //创建一个OkHttpClient的实例 OkHttpClient okHttpClient = new OkHttpClient(); //创建一个Request对象 Request request = new Request.Builder().url(address).build(); try { //调用OkHttpClient的newCall()方法来创建一个Call对象,通过它的execute()方法来发送请求并获取服务器返回的数据 Response response = okHttpClient.newCall(request).execute(); Log.d(TAG, "run: " + response.body().string()); } catch (IOException e) { e.printStackTrace(); } } }).start(); }
需要注意的是,发送网络请求属于耗时操作,无法在UI线程(主线程)进行,使用的时候一定单独起一个子线程去发送网络请求,否则会抛出android.os.NetworkOnMainThreadException的异常导致程序崩溃。
因此,OkHttp提供了一个回调接口,可供调用方有时机去处理服务器返回的数据
/*发送HTTP Get请求 * 参数: * address: 请求的url地址 * callback: OkHttp回调接口 * */public static void sendOkHttpRequest2(String address, Callback callback){ //创建一个OkHttpClient的实例 OkHttpClient okHttpClient = new OkHttpClient(); //创建一个Request对象 Request request = new Request.Builder().url(address).build(); //调用OkHttpClient的newCall()方法来创建一个Call对象 //enqueue()方法内部会开启一个子线程去执行http请求,并将最终的请求结果回调到Callback中 okHttpClient.newCall(request).enqueue(callback);}
调用方式:
HttpUtilty.sendOkHttpRequest("http://www.baidu.com", new Callback() { @Override public void onFailure(Call call, IOException e) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "http connected failed", Toast.LENGTH_SHORT).show(); } }); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, "onResponse: " + response.body().string()); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "success", Toast.LENGTH_SHORT).show(); } }); }});
需要注意的是,Callback最终的回调接口还是在okhttp起的子线程中运行的,因此不可以直接在回调接口里执行任何UI操作,可以借助runOnUiThread()方法来进行线程切换。
(2)Post请求
public static void sendOkHttpPostRequest(String address, Callback callback){ //创建一个OkHttpClient的实例 OkHttpClient okHttpClient = new OkHttpClient (); //构建一个RequestBody对象来存放待提交的参数 RequestBody requestBody = new FormBody.Builder() .add("username", "admin") .add("password", "123456") .build(); //创建一个Request对象 Request request = new Request.Builder() .url(address) .post(requestBody) .build(); //调用OkHttpClient的newCall()方法来创建一个Call对象 //enqueue()方法内部会开启一个子线程去执行http请求,并将最终的请求结果回调到Callback中 okHttpClient.newCall(request).enqueue(callback);}
三、WebView的使用方法
Android提供了一个WebView控件,借助它可以在自己的应用程序里嵌入一个浏览器,从而非常轻松的展示各种各样的网页。
1、创建一个布局文件,引入WebView控件
<?xml version="1.0" encoding="utf-8"?>
2、在Activity中使用WebView控件
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_http_demo); WebView webView = findViewById(R.id.webview); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient()); webView.loadUrl("http://www.baidu.com"); }
注意,这里使用了WevView的setWebViewClient()方法,并传入了一个WevViewClient的实例,作用是,希望目标网页仍然在当前WebView中展示,而不是打开系统浏览器。如果没有设置这个,那应用中会弹窗提示使用哪个浏览器打开目标网页,而不会在当前你自己的应用中展现网页。
更多相关文章
- EasyPermission Android(安卓)6.0 最简洁的权限框架
- android app设置亮屏的几种方式以及功耗对比
- react-native调用Android原生控件
- Android(安卓)边框圆角
- Android(安卓)TextView中文字设置超链接、颜色、字体 大杂烩
- Android(安卓)ViewPager 取消预加载
- android Xutils Http模块分析
- 为什么应用商店里搜索不到你的App?
- Android(安卓)Adapter 源码笔记(3)