【Android基础】二、网络编程

1、从网络中下载图片,使用HttpURLConnection进行访问网络的操作

2.访问网络的操作不能放在主线程中,开一个子线程通过发送消息到UI线程,在UI线程修改界面

Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    Toast.makeText(ImageActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
                    break;
                case 1:
                    ImageView imageView = (ImageView) findViewById(R.id.iv_pic);
                    //把位图对象显示在ImageView
                    imageView.setImageBitmap((Bitmap) msg.obj);
                    break;
                default:
                    break;
            }
        }
    };
public void download(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //1.确定网址
                String path = "http://192.168.56.1:8080/pic.jpg";
                try {
                    //2.把网址封装成一个URL对象
                    URL url = new URL(path);
                    //3.获取客户端和服务端的连接对象,此时还没有建立连接
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    //4.对连接对象进行初始化,设置请求方法,连接超时,读取超时
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(5000);
                    conn.setReadTimeout(5000);
                    //5.发送请求,与服务端建立连接
                    conn.connect();
                    //如果响应码为200,说明连接成功
                    if (conn.getResponseCode() == 200) {
                        //获取服务器响应头中的流,流的数据就是客户端请求的数据
                        InputStream is = conn.getInputStream();
                        //使用位图工厂对象从将流里的数据读取出来构造成位图对象
                        Bitmap bitmap = BitmapFactory.decodeStream(is);
                        Message msg = new Message();
                        msg.obj = bitmap;
                        msg.what = 1;
                        handler.sendMessage(msg);
                    } else {
                        Message msg = Message.obtain();
                        msg.what = 0;
                        handler.sendMessage(msg);
                    }

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

    }

3.图片缓存到本地,直接从本地读取
BtmapFactory对象直接从File中解压位图对象,参数为File文件的绝对路径

public void download(View v) {
        //1.确定网址
        final String path = "http://192.168.56.1:8080/pic.jpg";
        final File file = new File(getCacheDir(), "pic.jpg");
        if (file.exists()) {
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
            imageView.setImageBitmap(bitmap);
        } else {
            new Thread(new Runnable() {
                @Override
                public void run() {

                    try {
                        //2.把网址封装成一个URL对象
                        URL url = new URL(path);
                        //3.获取客户端和服务端的连接对象,此时还没有建立连接
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        //4.对连接对象进行初始化,设置请求方法,连接超时,读取超时
                        conn.setRequestMethod("GET");
                        conn.setConnectTimeout(5000);
                        conn.setReadTimeout(5000);
                        //5.发送请求,与服务端建立连接
                        conn.connect();
                        //如果响应码为200,说明连接成功
                        if (conn.getResponseCode() == 200) {
                            //获取服务器响应头中的流,流的数据就是客户端请求的数据
                            InputStream is = conn.getInputStream();
                            //使用位图工厂对象从将文件里的数据读取出来构造成位图对象
                            FileOutputStream fos = new FileOutputStream(file);
                            byte[] bytes = new byte[1024];
                            int len = 0;
                            if ((len = is.read(bytes)) != -1) {
                                fos.write(bytes,0,len);
                            }
                            fos.close();
                            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                            Message msg = new Message();
                            msg.obj = bitmap;
                            msg.what = 1;
                            handler.sendMessage(msg);
                        } else {
                            Message msg = Message.obtain();
                            msg.what = 0;
                            handler.sendMessage(msg);
                        }

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

3.从网络下载文本数据
这里使用字节数组输出流,读取输入流文本数据时,同步把数据写入字节数组输出流,直接通过字节数组输出流构造字符串返回,而不需要写入本地文件

 public String getTextFromStream(InputStream is){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int len = 0;
        try {
            if((len = is.read(b))!=-1){
                bos.write(b,0,len);
            }
            String text = new String(bos.toByteArray());
            return text;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

4.使用POST方法提交数据

 String data = "";
                        //添加POST请求的两行属性
                        conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
                        conn.setRequestProperty("Content-Length",data.length() + "");
                        //设置打开输出流,拿到输出流
                        conn.setDoOutput(true);
                        OutputStream os = conn.getOutputStream();
                        //使用输出流往服务器提交数据
                        os.write(data.getBytes());

二、多线程下载
需要两次请求网络
第一次请求网络获得文件长度,并且创建一个RandomAccessFile对象生成空的临时文件,设置临时文件的大小为获取的资源文件的长度,并计算每一个线程下载文件的起始位置和结束位置。

public void download() {
        new Thread() {
            @Override
            public void run() {
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(5000);
                    conn.setReadTimeout(5000);
                    conn.connect();
                    if (conn.getResponseCode() == 200) {
                        //获得网络请求返回的流的字节长度
                        int length = conn.getContentLength();
                        File file = new File(Environment.getExternalStorageDirectory(),"QQ.exe");
                        //使用随机存文件对象生成临时文件
                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                        //设置临时文件的大小
                        raf.setLength(length);
                        //计算出每一个线程应该下载多少字节
                        int size = length / THREADCOUNT;
                        for (int i = 0; i < THREADCOUNT; i++) {
                            //计算每一个线程下载的起始位置和结束位置
                            int startIndex = i * size;
                            int endIndex = (i + 1) * size - 1;
                            if (i == THREADCOUNT - 1) {
                                endIndex = length - 1;
                            }
                            new DownloadThread(startIndex, endIndex, i).start();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

第二次请求网络下载文件。通过Range属性设置线程的请求数据区间,请求部分数据成功的返回码为206,还需要设置写入文件的起始位置raf.seek()

断点续传:创建一个临时文件记录线程的下载进度,再次下载时读取临时文件,修改下载区间

class DownloadThread extends Thread {
    int startIndex;
    int endIndex;
    int threadId;

    public DownloadThread(int startIndex, int endIndex, int threadId) {
        this.startIndex = startIndex;
        this.endIndex = endIndex;
        this.threadId = threadId;
    }

    @Override
    public void run() {
        try {
            File progressFile = new File(threadId + ".txt");
            if (progressFile.exists()) {
                FileInputStream fis = new FileInputStream(progressFile);
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                startIndex += Integer.parseInt(br.readLine());
            }

            URL url = new URL(MutiThreadActivity.path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            //设置本次请求的数据区间
            conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
            if (conn.getResponseCode() == 206) {
                InputStream is = conn.getInputStream();
                byte[] b = new byte[1024];
                int len = 0;
                int total = 0;
                File file = new File(Environment.getExternalStorageDirectory(),"QQ.exe");
                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                //设置写入文件的开始位置
                raf.seek(startIndex);
                while ((len = is.read(b)) != -1) {
                    raf.write(b, 0, len);
                    total += len;
                    RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
                    progressRaf.write((total + "").getBytes());
                    progressRaf.close();
                }
                raf.close();
                //全部下载完毕后删除临时记录文件
                MutiThreadActivity.finishThread++;
                synchronized (MutiThreadActivity.path) {
                    for (int i = 0; i < MutiThreadActivity.THREADCOUNT; i++) {
                        File f = new File(threadId + ".txt");
                        f.delete();
                    }
                    MutiThreadActivity.finishThread = 0;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用到的输入输出流:
RandomAccessFile:可以设置写入的位置
FileOutputStream:直接写入文件中
ByteArrayOutputStream:写入的数据存储在一个字节数组中,转换成字节数组,创建字符串
InputStream:读取数据到一个字节数组中
BufferedReader:按行读取,返回一个String,参数是InputStreamReader(FileInputStream)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值