网络技术之——网络连接URLConnection、单/多线程下载

来源:互联网 发布:js给input添加样式 编辑:程序博客网 时间:2024/06/05 00:49

“网络连接”:

android中的HTTP的网络连接中HttpURLConnection方法和java中的HttpURLConnection用法是一致的,参考:
day0812-doGet和doPost
但在6.0之后,舍弃了HttpClient方法。

1.概述:


网络连接不允许在主线程中进行(3.0之前是允许的),所以通常情况我们都利用异步来操作,方式,利用Handler和AsyncTask.

这里我们介绍三种方式来访问网络:
普通URLConnection和HTTP协议访问(http访问包括HttpURLConnectionHttpClient两种)

2.用法:

URLConnection:

**<一>使用步骤:
注:在子线程中连接服务器。

1)获取URLConnection实例:

URL url = new URL("http://192.168.0.74:8080/myServer/Myserverlet");URLConnection connection = url.openConnection();

2)获得服务器返回的输入流

InputStream is = connection.getInputStream();

3)接下来,就是对数据流进行读取。

4)最后别忘了,联网需要权限的设置:

这里写图片描述
**<二>范例:
功能:利用URLConnection连接服务器,并将从服务器返回的的数据显示到textview中。
思路:先建立子线程,连接服务器,由于线程中获得的数据需要传给活动,绘制Textview,所以采用异步中的Handler方法主活动接收消息。

1.连接网络:
这里写图片描述

这里将获得的数据存到buffer缓存中,获得主线程的Handler,并发送。最后别忘了关闭流。
注:这里连接的是自己创建的服务器,但由于用手机模拟器模拟,其本身也是有地址的,所以不能用localhost,要用电脑主机地址。

2.开启线程:
这里写图片描述

一定不要忘了start线程。

3.创建主活动中的Handler子类:
这里写图片描述
效果图:
这里写图片描述

HttpURLConnection:

**<一>使用步骤:
HttpURLConnection与URLConnection用法基本相同:

1)获得实例:

URL url = new URL("http://192.168.0.74:8080/myServer/Myserverlet");HttpURLConnection connection = (HttpURLConnection)url.openConnection();

2)设置HTTP请求的方式(GET和POST)以及其他自由定制:

connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);connection.setReadTimeout(8000);

3)获得输入流并进行读取。

InputStream is = connection.getInputStream();

4)最后关闭HTTP连接:

connection.disconnect();

5)权限不要忘了。

**<二>更改上面范例:
doGet:

URL url = new URL("http://360.com");            URLConnection connect = (URLConnection) url.openConnection();            // 3.强制造型成httpUrlConnection            HttpURLConnection httpConnection = (HttpURLConnection) connect;            // 4.设置请求方式            httpConnection.setRequestMethod("GET");            httpConnection.setConnectTimeout(3000);// 连接chaoshi            httpConnection.setReadTimeout(3000); // 等待返回时间超时            InputStream is = httpConnection.getInputStream();

“下载文件”:

单线程下载:

1)方法:

下载一般放在后台,即开启服务去进行,且需要开启一个新的线程。

2)范例:单线程下载服务器文件

功能:
服务器中有一音乐文件,地址为:http://192.168.0.74:8080/myServer/music/apple.mp3
这里采用单线程去下载,此例使用AsyncTask异步线程的方法,当然也可以使用Handler去开启一个异步线程。

下载文件的线程:

    //创建一个线程下载文件,利用AsyncTask    class MyAsyncTask extends AsyncTask<String, Integer, String>{        @Override        protected void onPostExecute(String result) {            // TODO Auto-generated method stub            super.onPostExecute(result);        }        @Override        protected void onProgressUpdate(Integer... values) {            // TODO Auto-generated method stub            super.onProgressUpdate(values);            int progress = (int)((values[0]*(100.0))/values[1]);            Log.d("message", values[1]+""+values[0]);            //proBar.setMax(values[1]);//利用比例来调整bar的值,并不用设置setmax。            proBar.setProgress(progress);        }        @Override        protected String doInBackground(String... arg0) {            // TODO Auto-generated method stub            try {                URL uri = new URL("http://192.168.0.74:8080/myServer/music/apple.mp3");                URLConnection connection = uri.openConnection();// 建立连接                int length = connection.getContentLength();//获得文件总长度                InputStream is = connection.getInputStream();//获得流                //输出流,写到自己文件中                File file = new File(Environment.getExternalStorageDirectory(),"apple3.mp3");                //判断文件是否存在了                if(!file.exists()){                    file.createNewFile();                }                FileOutputStream os = new FileOutputStream(file);                byte[] array = new byte[1024];//写到数组中                int sum = 0;//写入的总长度                int index = is.read(array);                while(index!=-1){                    os.write(array, 0, index);                    sum+=index;//长度变化                    index=is.read(array);                    publishProgress(sum,length);//将下载进度和总长度传到onProgressUpdate方法中改吧seekbar                }                os.flush();                os.close();                is.close();            } catch (MalformedURLException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            return null;        }    };

分析:将下载的进程传到onProgressUpdate方法中进行更新,传过来的参数还有文件的总长度:
这里写图片描述

进度条进度的设置,设置成百分比:
进度*100.0/总长度

这里写图片描述
点击事件中开启线程:
这里写图片描述
读写权限:
这里写图片描述

综合上面实例的效果演示:
这里写图片描述


注:下载后的文件所存放的位置在输出流的地址文件中,即:

File file = new File(Environment.getExternalStorageDirectory(),"apple3.mp3");

设置了下载到文件在SD卡下:apple.mp3文件中

多线程下载:

这里写图片描述

思路:建立一个线程,专门用于打开连接,并开启其他多个线程进行下载,每个线程分管一段,但往往并不能正好分完,所以最后一个线程可以将剩余的全部下载完。

1)建立线程,打开连接,并开启其他线程进行下载。这里进行的其他操作是,需要将用于下载的线程存储到数组中,用于开启后,每秒得到所有线程的进度总和

new Thread(new Runnable() {                @Override                public void run() {                    try {                        String urlPath="http://192.168.0.30:8080/MyWebTest/music/aa.mp3";                        URL  url = new URL(urlPath);                        URLConnection connection=url.openConnection();//建立连接                         length=connection.getContentLength();//获得文件长度                        File file=new File(Environment.getExternalStorageDirectory(),"cc.mp3");//创建写入的路径                        if(!file.exists()){                            file.createNewFile();                        }                        MultiThread[] threads=new MultiThread[5];//建立一个数组用于存储5个线程                        for (int i=0;i<5;i++){                            MultiThread thread=null;//建立5个线程 ,MultiThread类是自定义的线程类****                            if(i==4){                                thread = new MultiThread(length / 5*4, length , urlPath, file.getAbsolutePath());                            }else {                                 thread = new MultiThread(length / 5 * i, length / 5 * (i + 1)-1, urlPath, file.getAbsolutePath());                            }                            thread.start();                            threads[i]=thread;                        }/*获取各个线程下载的进程的总和,显示到进度条,用于上面存到数组中的线程*/                        boolean isFinish=true;                        while(isFinish){                            int sum=0;                            for (MultiThread thread:threads){//获得每个线程中的进程,getSum方法                                sum+= thread.getSum();                            }                              Message msg=  handler.obtainMessage();//用handler将获得的进度和传给活动,并显示                            msg.what=0x23;                            msg.arg1=sum;                            handler.sendMessage(msg);                            if(sum+10>=length){//为避免死循环,当下载到文件中长度时停止下载                                isFinish=false;                            }                            Thread.sleep(1000);//每休眠1s一获得每个线程的下载进度                        }                    } catch (MalformedURLException e) {                        e.printStackTrace();                    } catch (IOException e) {                        e.printStackTrace();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();

注:thread = new MultiThread(length / 5 * i, length / 5 * (i + 1)-1, urlPath, file.getAbsolutePath());
由于setRequestProperty是包前包后的,所以这里在传入start和end时,end应该-1.
2)用于下载的线程:这里创建 了5个

public class MultiThread extends Thread{    /*创建构造器,需要传入下载的开始位置,结束位置,要下载的url地址,以及下载到的地址    */        public MultiThread(long start, long end, String url, String filePath) {            this.start = start;            this.end = end;            this.urlPath = url;            this.filePath = filePath;        }        private int sum=0;//用于记录每个线程下载的进度        private long start;        private long end;        private String urlPath;        private String filePath;        public int getSum() {//用于获得该线程的下载进度            return sum;        }        @Override        public void run() {            try {                URL url=new URL(urlPath);                URLConnection connection=url.openConnection();            /*下载指定位置文件*/                connection.setAllowUserInteraction(true);                connection.setRequestProperty("Range", "bytes=" + start + "-"                        + end);                 InputStream is= connection.getInputStream();                byte [] array=new byte[1024];                is.read(array);                File file=new File(filePath);            /*下载到指定的位置,即从文件的哪里开始写入*/                RandomAccessFile randomAccessFileile=new RandomAccessFile(file,"rw");                randomAccessFileile.seek(start);                int index=is.read(array);                while (index!=-1){                    randomAccessFileile.write(array,0,index);                    sum+=index;                    index=is.read(array);                }                randomAccessFileile.close();                is.close();            } catch (MalformedURLException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }        }}


特殊的代码:从指定的开始位置和结束位置进行下载setRequestProperty方法

这里写图片描述

从指定位置开始写入:RandomAccessFile类

这里写图片描述
3)活动接收进度值,并显示到进度条中:
这里写图片描述
效果演示:

注:
1>先打开服务器,否则无法下载其路径下的文件。
2>且路径“http://192.168.0.74:8080/myServer/music/apple.mp3”
myServer:是服务器名称,
music/apple.mp3:music文件夹下的apple.mp3

这里写图片描述

0 0
原创粉丝点击