从网络中下载文件保存到SD卡和显示下载进度

任务:

1.从网络中下载文件存储到SD卡

2.显示下载进度

人丑话不多,直接撸代码。

xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击我开始下载"
        android:id="@+id/btn_download"
        />


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载进度:"
        android:layout_marginTop="40dp"/>


    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="100"
        />

</LinearLayout>

java代码:

package com.example.jiaho.handleproject;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class DownLoadActivity extends AppCompatActivity {

    public static final int DOWNLOAD_MESSAGE_CODE = 10001;
    public static final int DOWNLOAD_MESSAGE_FAIL_CODE = 10002;
    public static final String AppURL = "http://192.168.31.138/mukewang.apk";
    private Button btn_download;
    private ProgressBar progressBar;
    private Handler mHandler;
    private static final int REQUEST_EXTERNAL_STORAGE=1;
    private static String[] PERMISSIONS_STORAGE={
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_download);
        btn_download=findViewById(R.id.btn_download);
        progressBar=findViewById(R.id.progressBar);
        /*
        * 主线程
        * 1.点击按键
        * 2.发起下载
        * 3.开启子线程做下载
        * 4.下载过程中通知主线程    ------>   主线程更新进度条
        * */

        btn_download.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //在子线程中执行download方法
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        download(AppURL);
                    }
                }).start();
            }
        });

        //接收子线程的消息
        mHandler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //处理消息
                switch (msg.what){
                    case DOWNLOAD_MESSAGE_CODE:
                        progressBar.setProgress((int)msg.obj);
                        break;
                    case DOWNLOAD_MESSAGE_FAIL_CODE:
                        Toast.makeText(DownLoadActivity.this,"下载失败",Toast.LENGTH_SHORT).show();
                }
            }
        };

    }

    public void download(String appUrl){
        try {
            //拿到Url
            URL url=new URL(appUrl);
            //打开一个connect
            URLConnection urlConnection=url.openConnection();
            //获取输入流
            InputStream inputStream=urlConnection.getInputStream();
            //获取文件的总长度
            int contentLength=urlConnection.getContentLength();

            //创建一个下载路径
            String downloadFolderName= Environment.getExternalStorageDirectory()+File.separator+"imooc"+File.separator;
            //创建一个文件
            File file=new File(downloadFolderName);

            if(!file.exists()){
                //如果文件不存在,就创建一个文件
                file.mkdir();
            }

            //创建文件
            String fileName=downloadFolderName+"mkapp.apk";
            File fileMove=new File(fileName);

            //如果文件存在就把它删掉,下次运行程序就不会报错
            if (fileMove.exists()){
                fileMove.delete();
            }

            //记录下载的大小
            int downloadSize=0;
            byte[] bytes=new byte[1024];
            int length=0;
            //创建一个输出流
            //verifyStoragePermissions(DownLoadActivity.this);
            OutputStream outputStream=new FileOutputStream(fileName);
            while ((length=inputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,length);
                downloadSize+=length;
                /*
                * 每完成一点下载,就及时更新UI
                * */
                Message message = Message.obtain();
                //提取出一个静态变量
                message.what = DOWNLOAD_MESSAGE_CODE;
                message.obj=(downloadSize/contentLength)*100;
                //将消息通过Handle发出去
                mHandler.sendMessage(message);
            }

        }catch (MalformedURLException e){
            //如果下载失败了,也要发送下载失败的消息
            NotifyDownLoadFail();
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
            NotifyDownLoadFail();
        }

    }

    //提取出一个方法
    private void NotifyDownLoadFail() {
        Message message=Message.obtain();
        message.what= DOWNLOAD_MESSAGE_FAIL_CODE;
        mHandler.sendMessage(message);
    }

    //检查权限的方法,android6.0才需要在java代码中实现权限赋予
    public static void verifyStoragePermissions(Activity activity){
        //Check if we have write permission
        int permission = ActivityCompat.checkSelfPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission!= PackageManager.PERMISSION_GRANTED){
            //没有权限,则通知用户
            ActivityCompat.requestPermissions(activity,PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
        }
    }
}

解释一下代码段:

//检查权限的方法,android6.0才需要在java代码中实现权限赋予
    public static void verifyStoragePermissions(Activity activity){
        //Check if we have write permission
        int permission = ActivityCompat.checkSelfPermission(activity,Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission!= PackageManager.PERMISSION_GRANTED){
            //没有权限,则通知用户
            ActivityCompat.requestPermissions(activity,PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
        }
    }

这个代码在android6.0上才被需要,因为当时写代码时,老是提示权限不够,就在网上查各种资料,所以各种变态权限都试了一遍,足足尝试了2个多小时,发现还是不行。后来我就纳闷了,我的android才4.4啊,根本不需要这些才对啊。于是我重新认真检查代码,发现了一个隐藏至深的bug,真是痛心疾首,老夫捶胸顿足,差点一口老血喷了出来。原来是我写文件路径的时候,将代码File.separator写成了File.pathSeparator。

简单讲下File.separator和File.pathSeparator的区别:

File.pathSeparator指的是分隔连续多个路径字符串的分隔符,例如:

java -cp test.jar;hello.jar

就是指";"

 File.separator才是用来分隔同一个路径字符串中的目录,例如:

E:\Android\androidProject

就是指"\"

猜你喜欢

转载自blog.csdn.net/CjhLoveAndroid/article/details/82811365