Android网络 | URL和URLConnection详解及其实战案例

简介: Android网络 | URL和URLConnection详解及其实战案例

URL和URLConnection

  • **URL(Uniform Resource Locator)对象代表统一资源定位器

指向互联网“资源”指针
这里的资源可以是简单的文件或目录
也可以是对更为复杂的对象引用
例如对数据库搜索引擎查询。**

  • **通常情况而言,

URL可以由协议名、主机、端口和资源组成,
满足如下的格式
protocol://host:port/resourceName**

  • **例如下面就是一个合法的URL地址:

http://www.oneedu.cn/Index.htm**

  • **在Android系统中可以通过URL获取网络资源,

其中的URLConnectionHTTPURLConnection
是最为常用的两种方式。**

URL类详解

  • **在JDK中还提供了一个URI(Uniform Resource Identifiers)类,

其实例代表一个统一资源标识符
Java的URI不能用于定位任何资源
它的唯一作用就是解析。**

  • **与此对应的是,

URL包含一个可打开到达该资源输入流
因此我们可以将URL理解成URI的特例。**

  • **在类URL中,

提供了多个可以创建URL对象的构造器
一旦获得了URL对象之后,
可以调用下面的方法来访问该URL对应的资源。**

- `String getFile()`:获取此URL的`资源名`。

- `String getHost()`:获取此URL的`主机名`。
- `String getPath()`:获取此URL的`路径部分`。
- `int getPort()`:获取此URL的`端口号`。
- `String getProtocol()`:获取此URL的`协议名称`。
- `String getQuery()`:获取此URL的`查询字符串部分`。
- `URLConnection openConnection()`:

返回一个URLConnection对象
它表示到URL所引用的远程对象的连接

- `InputStream openStream()`:

打开与此 URL 的连接
并返回一个用于读取该 URL 资源InputStream

  • **在URL中,

可以使用方法openConnection()返回一个URLConnection对象,
该对象表示应用程序URL之间的通信链接。**

  • **应用程序可以通过URLConnection实例

向此URL发送请求
并读取URL引用的资源
创建一个和URL连接
并发送请求;**

  • 读取此URL引用的资源的步骤:

    • (1)通过调用URL对象openConnection()方法来创建URLConnection对象。
    • (2)设置URLConnection参数普通请求属性
    • (3)如果只是发送 Get 方式请求,使用方法 connect

建立和远程资源之间的实际连接即可;
如果需要发送Post方式请求,
需要获取URLConnection实例对应的输出流来发送请求参数

- (4)`远程资源`变为`可用`,

程序可以访问远程资源的头字段或通过输入流
读取远程资源的数据


  • 建立和远程资源的实际连接之前

可以通过如下方法来设置请求头字段

- `setAllowUserInteraction`:设置该URLConnection的allowUserInteraction请求头字段的值。

- `setDoInput`:设置该URLConnection的doInput请求头字段的值。
- `setDoOutput`:设置该URLConnection的doOutput请求头字段的值。
- `setIfModifiedSince`:设置该URLConnection的ifModifiedSince请求头字段的值。
- `setUseCaches`:设置该URLConnection的useCaches请求头字段的值。

除此之外,还可以使用如下方法来设置或增加通用头字段。

- `setRequestProperty(String key, String value)`:设置该URLConnection的key请求头字段的值为value。
- `addRequestProperty(String key, String value)`:为该URLConnection的key请求头字段的增加value值,该方法并不会覆盖原请求头字段的值,而是将新值追加到原请求头字段中。


  • 当发现远程资源可以使用后,

使用如下方法访问头字段和内容

- `Object getContent()`:获取该URLConnection的内容。
- `String getHeaderField(String name)`:获取指定响应头字段的值。
- `getInputStream()`:返回该URLConnection对应的输入流,用于获取URLConnection响应的内容。
- `getOutputStream()`:返回该URLConnection对应的输出流,用于向URLConnection发送请求参数。
- `getHeaderField`:根据响应头字段来返回对应的值。

因为在程序中需要经常访问某些头字段,所以Java为我们提供了如下方法来访问特定响应头字段的值。

- `getContentEncoding`:获取content-encoding响应头字段的值。
- `getContentLength`:获取content-length响应头字段的值。
- `getContentType`:获取content-type响应头字段的值。
- `getDate()`:获取date响应头字段的值。
- `getExpiration()`:获取expires响应头字段的值。
- `getLastModified()`:获取last-modified响应头字段的值。
案例1:InetAddress的简单用法:
public class UseInetAddress {

    public UseInetAddress() {
        // TODO Auto-generated constructor stub
    }

    public static void main(String[] args)
            throws Exception
        {
            //根据主机名来获取对应的InetAddress实例
            InetAddress ip = InetAddress.getByName("www.sohu.com");
            
            //判断是否可达
            System.out.println("sohu是否可达:" + ip.isReachable(2000));
            
            //获取该InetAddress实例的IP字符串
            System.out.println(ip.getHostAddress());
            
            //根据原始IP地址来获取对应的InetAddress实例
            InetAddress local = InetAddress.getByAddress(new byte[]{127,0,0,1});            
            System.out.println("本机是否可达:" + local.isReachable(5000));
            
            //获取该InetAddress实例对应的全限定域名
            System.out.println(local.getCanonicalHostName());
        }

}

运行效果:

sohu是否可达:true
14.18.240.22
本机是否可达:true
127.0.0.1
凌川江雪阁是否可达:true
47.100.78.251
案例2:普通字符和MIME字符的转换

注意:

  • encode编码;decode解码/译码;
  • 编码和解码所用的编码标准(UTF-8/GBK)要一样!

比方说,某一个普通String,
encode用的标准是UTF-8,
那编码出来的码在decode时,
用的标准也要是UTF-8,方可译码,
否则用GBK是无法解码的!

public class URLDecodery {

    public static void main(String[] args) 
            throws Exception
    {
        //将application/x-www-form-urlencoded MIME字符串
        //转换成普通字符串
        String keyWord = URLDecoder.decode(
          "%CE%CA%CA%C0%BC%E4%C7%E9%CE%AA%BA%CE%CE%EF", "GBK");
        System.out.println(keyWord);
        
        //将普通字符串转换成
        //application/x-www-form-urlencoded MIME字符串
        String urlStr = URLEncoder.encode("直教人生死相许" , "GBK");
        System.out.println(urlStr);
            
        keyWord = URLDecoder.decode("%E7%8B%97%E7%8B%97%E6%90%9E%E7%AC%91", "UTF-8");
        System.out.println(keyWord);
        
    }

}

运行结果:

问世间情为何物
%D6%B1%BD%CC%C8%CB%C9%FA%CB%C0%CF%E0%D0%ED
狗狗搞笑



HttpURLConnection详解

主要分四个功能实现:

  1. 从Internet获取网页

需要先发送请求,
然后将网页以流的形式读回来:

(1)创建一个URL对象:

    URL url = new URL("http://www.sohu.com");

(2)利用HttpURLConnection对象从网络中获取网页数据:

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

(3)设置连接超时:

    conn.setConnectTimeout(6* 1000);

(4)对响应码进行判断:

    if (conn.getResponseCode() != 200) throw new RuntimeException("请求url失败");

(5)得到网络返回的输入流:

    InputStream is = conn.getInputStream();

接着可以用bufferReader读取数据;

  1. 从Internet获取文件

(1)~(5)同上
(6)写出得到的文件流:

    outStream.write(buffer, 0, len);
  1. 向Internet发送请求参数

(1)将地址和参数存到byte数组中:

    byte[] data = params.toString().getBytes();

(2)创建URL对象:

URL realUrl = new URL(requestUrl);

(3)用HttpURLConnection对象向网络地址发送请求:

HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();

(4)设置容许输出:

conn.setDoOutput(true);

(5)设置不使用缓存:

conn.setUseCaches(false);

(6)设置使用Post的方式发送:

conn.setRequestMethod("POST");

(7)设置维持长连接:

conn.setRequestProperty("Connection", "Keep-Alive");

(8)设置文件字符集:

conn.setRequestProperty("Charset", "UTF-8");

(9)设置文件长度:

conn.setRequestProperty("Content-Length", String.valueOf(data.length));

(10)设置文件类型:

conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");

(11)最后以流的方式输出。

在实现此功能时,
在发送Post请求时必须设置允许输出。
建议不要使用缓存,避免出现不应该出现的问题。
在开始就用HttpURLConnection对象的setRequestProperty()设置,
即生成HTML文件头。
####当然,具体的还可以参考郭神的写法:
HttpURLConnection

OKHttp

  1. 向Internet发送XML数据

可参考其他博客,这里不再赘述

注意
使用Android中的HttpUrlConnection时,有个地方需要注意一下,
就是如果程序中有跳转,并且跳转有外部域名的跳转,
那么非常容易超时并抛出域名无法解析的异常(Host Unresolved),
建议做跳转处理的时候不要使用它自带的方法设置成为自动跟随跳转,
最好自己做处理,以防出现异常。
这个问题模拟器上面看不出来,只有真机上面能看出来。

案例1:在Android手机屏幕中显示网络中的图片

  • **在日常应用中,

我们经常不需要将网络中的图片 保存到手机中
而只是在网络浏览一下即可。

这里用 HttpURLConnection 打开连接,
即可获取连接数据了。
在本实例中,
使用HttpURLConnection方法来连接获取网络数据
获取的数据InputStream的方式保存内存中。**

**注意:
这里必须把 网络请求这个 耗时操作放在 子线程
否则可能会 阻塞主线程,造成报错!
(各种乱起八糟的错误,
IDE待会儿 什么v4和v7组件库版本不匹配的错误都给你搬出来。。。)

主要思路是:
子线程中进行 网络请求
具体的 网络请求操作如上所述
(这里用的是 HttpURLConnection去连接 远程资源
实际开发中可以尝试集成第三方库),
请求成功
把得到的资源在子线程编码( decodeStream())成 bitmap
接着把 bitmap转交到 主线程进行 UI更新即可完成!**
  • 方式一:直接用runOnUiThread()bitmap转交到主线程进行UI更新
public class GetImageActivity extends AppCompatActivity {

    private Button mButton1;
    private TextView mTextView1;
    private ImageView mImageView1;

    String uriPic = "http://www.baidu.com/img/baidu_sylogo1.gif";

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_get_image);

        mButton1 = (Button) findViewById(R.id.myButton1);
        mTextView1 = (TextView) findViewById(R.id.myTextView1);
        mImageView1 = (ImageView) findViewById(R.id.myImageView1);

        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                /* 设置Bitmap在ImageView中 */
                getURLBitmap();

            }
        });
    }

    public void getURLBitmap()
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                URL imageUrl = null;
                Bitmap bitmap = null;

                try {
                    /* new URL对象将网址传入 */
                    imageUrl = new URL(uriPic);
                } catch (MalformedURLException e)
                {
                    e.printStackTrace();
                }

                try {
                    /* 取得连接 */
                    HttpURLConnection conn = (HttpURLConnection) (imageUrl != null ? imageUrl.openConnection() : null);
                    if (conn != null) {
                        conn.connect();
                    }

                    /* 取得返回的InputStream */
                    InputStream is = null;
                    if (conn != null) {
                        is = conn.getInputStream();
                    }

            /* !!!!!!!!!!!
            将InputStream变成Bitmap
            !!!!!!!!!!!!!*/
                    bitmap = BitmapFactory.decodeStream(is);

                    showImage(bitmap);

                    /* 关闭InputStream */
                    if (is != null) {
                        is.close();
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void showImage(final Bitmap bitmap) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mImageView1.setImageBitmap(bitmap);
                mTextView1.setText("");
            }
        });
    }
}

对应的xml布局:

<?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:background="#FFFFFF"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/myTextView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/app_name"/>

    <Button
        android:id="@+id/myButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="获取网络上的图片" />

    <ImageView
        android:id="@+id/myImageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        tools:ignore="ContentDescription" />

</LinearLayout>

运行结果:

  • 方式二:使用handle消息机制bitmap转交到主线程进行UI更新
public class GetImageActivityTwo extends AppCompatActivity {

    ImageView iv_show;
    EditText et_path;
    String path;

    @SuppressLint("HandlerLeak")
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {

            Bitmap bitmap = (Bitmap) msg.obj;
            iv_show.setImageBitmap(bitmap);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_get_image_two);
        //寻找相应控件
        et_path = findViewById(R.id.et_path);
        iv_show = findViewById(R.id.iv_show);
    }

    public void click(View v){
        new Thread(){
            Message message = Message.obtain();
            @Override
            public void run() {

                File file = new File(getCacheDir(),"test.png");
                if(file.exists() && file.length()>=0){
                    //如果要缓存
//                    System.out.print("本地缓存");
//                    Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
//                    message.obj = bitmap;
//                    handler.sendMessage(message);
                }

                else{

                    path = et_path.getText().toString().trim();
                    try {
                        URL url = new URL(path);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        conn.setRequestMethod("GET");//设置请求方法
                        conn.setConnectTimeout(5000);//设置超时时间
                        InputStream in = conn.getInputStream();//拿到服务器返回的输出流
                        Bitmap bitmap = BitmapFactory.decodeStream(in);
                        message.obj = bitmap;
                        message.what = 2;
                        handler.sendMessage(message);//发送消息

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

xml布局:

<?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"
    android:orientation="vertical"
    tools:context=".UI.GetImageActivityTwo">

    <EditText
        android:id="@+id/et_path"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="http://www.baidu.com/img/baidu_sylogo1.gif"
        android:hint="请输入图片地址" />

    <Button
        android:onClick="click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查看" />

    <ImageView
        android:id="@+id/iv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

运行结果:





  • 参考《精通Android网络开发》
相关文章
|
1月前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin协程优化网络请求处理
【2月更文挑战第30天】 在移动应用开发领域,网络请求的处理是影响用户体验的关键环节。针对Android平台,利用Kotlin协程能够极大提升异步任务处理的效率和简洁性。本文将探讨如何通过Kotlin协程优化Android应用中的网络请求处理流程,包括协程的基本概念、网络请求的异步执行以及错误处理等方面,旨在帮助开发者构建更加流畅和响应迅速的Android应用。
|
1月前
|
安全 网络安全 数据安全/隐私保护
【计算机网络】URL概念及组成
【计算机网络】URL概念及组成
|
3月前
Android4.1.0实战教程---自动阅读小说
Android4.1.0实战教程---自动阅读小说
37 0
|
3月前
|
监控 Android开发 C语言
深度解读Android崩溃日志案例分析2:tombstone日志
深度解读Android崩溃日志案例分析2:tombstone日志
84 0
|
1天前
android-agent-web中js-bridge案例
android-agent-web中js-bridge案例
9 2
|
1天前
|
移动开发 Java Android开发
构建高效Android应用:采用Kotlin协程优化网络请求
【4月更文挑战第24天】 在移动开发领域,尤其是对于Android平台而言,网络请求是一个不可或缺的功能。然而,随着用户对应用响应速度和稳定性要求的不断提高,传统的异步处理方式如回调地狱和RxJava已逐渐显示出局限性。本文将探讨如何利用Kotlin协程来简化异步代码,提升网络请求的效率和可读性。我们将深入分析协程的原理,并通过一个实际案例展示如何在Android应用中集成和优化网络请求。
|
1天前
|
数据采集 存储 人工智能
【AI大模型应用开发】【LangChain系列】实战案例2:通过URL加载网页内容 - LangChain对爬虫功能的封装
【AI大模型应用开发】【LangChain系列】实战案例2:通过URL加载网页内容 - LangChain对爬虫功能的封装
8 0
|
9天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
10 0
|
9天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
9 0
|
1月前
|
缓存 移动开发 Java
构建高效Android应用:内存优化实战指南
在移动开发领域,性能优化是提升用户体验的关键因素之一。特别是对于Android应用而言,由于设备和版本的多样性,内存管理成为开发者面临的一大挑战。本文将深入探讨Android内存优化的策略和技术,包括内存泄漏的诊断与解决、合理的数据结构选择、以及有效的资源释放机制。通过实际案例分析,我们旨在为开发者提供一套实用的内存优化工具和方法,以构建更加流畅和高效的Android应用。