Android使用线程池或者DownloadManager在线更新apk

万俟小林
2023-12-01

 

一、使用线程池分段下载,然后再合并文件

public class Main {

    private static final String url = "https://d9f43c992961ae0750505398dbb4823c.dd.cdntips.com/imtt.dd.qq.com/16891/apk/9C52689F0451CBFBDBBF535ADD40D3A7.apk?mkey=5e9fdcc9777b5f80&f=24c3&fsname=com.tencent.weishi_6.7.6.588_676.apk&csr=1bbd&cip=119.123.121.117&proto=https";

    public static void main(String[] args) throws IOException {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        conn.setRequestProperty("connection", "keep-alive");
        int fileLength = conn.getContentLength();
        System.out.println("文件长度:" + fileLength);
        int theadCount = 3;
        int size = fileLength / theadCount;
        System.out.println("每个下载量:" + size);
        conn.disconnect();
        File file = new File("D:\\ws.apk");
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        MyTask task0 = new MyTask(0, 0, size - 1, file);
        MyTask task1 = new MyTask(1, size, (2 * size) - 1, file);
        MyTask task2 = new MyTask(2, 2 * size, fileLength, file);
        fixedThreadPool.execute(task0);
        fixedThreadPool.execute(task1);
        fixedThreadPool.execute(task2);
        fixedThreadPool.shutdown();
    }

    static class MyTask implements Runnable {

        private final int taskNum;
        private final int startPos;
        private final int endPos;
        private final File file;

        public MyTask(int taskNum, int startPos, int endPos, File file) {
            this.taskNum = taskNum;
            this.startPos = startPos;
            this.endPos = endPos;
            this.file = file;
        }

        @Override
        public void run() {
            try {
                HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty("connection", "keep-alive");
                //设置下载区间
                conn.setRequestProperty("range", "bytes=" + startPos + "-" + endPos);

                conn.connect();
                int code = conn.getResponseCode();
                if (code == 206) {
                    InputStream in = conn.getInputStream();
                    int serverSize = conn.getContentLength();
                    System.out.println("服务器返回的长度:" + serverSize);
                    System.out.println("bytes=" + startPos + "-" + endPos);
                    System.out.println(Thread.currentThread().getName() + "---" + taskNum);
               
                    RandomAccessFile out = new RandomAccessFile(file, "rw");
                    out.seek(startPos);
                    byte[] b = new byte[1024];
                    int len = -1;
                    while ((len = in.read(b)) != -1) {
                        out.write(b, 0, len);
                    }
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

二、使用android自带的DownloadManager下载更新apk

        val downloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
        val request = DownloadManager.Request(Uri.parse(apkUrl))

        //指定WiFi下才下载
        //request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI)
        //指定MOBILE状态下才下载
        //request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE)
        //是否允许漫游下下载
        //request.setAllowedOverRoaming(false)
        //是否允许 计量式网络连接 下载
        //request.setAllowedOverMetered(true)//默认为true

        //取消下载(如果下载被取消,所下文件会被删除)
        //downloadManager.remove(id)

        //显示还是隐藏
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
        //设置notification的标题和描述
        request.setTitle("下载文件标题")
        request.setDescription("下载文件描述")

        //设置下载文件类型
        request.setMimeType("application/vnd.android.package-archive")

        //请求头等信息
        //request.addRequestHeader("","")

        //保存文件路径,当前应用目录下file/downloads
        request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "demo.apk")

        var id: Long = 0
        button.setOnClickListener {
            //每下载一个文件对应一个id,通过id可以查询数据
            id = downloadManager.enqueue(request)
        }

        //使用handler和Timer更新进度条
        val handler = @SuppressLint("HandlerLeak")
        object : Handler() {
            @SuppressLint("HandlerLeak")
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                val progress = msg.data.getInt("pro")
                bar.progress = progress
            }
        }
        val timer = Timer()
        val task = object : TimerTask() {
            override fun run() {
                val cursor =         downloadManager.query(DownloadManager.Query().setFilterById(id))
                if (cursor != null && cursor.moveToFirst()) {
                    //获取下载状态信息
                    if (cursor.getInt(
                            cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
                        ) == DownloadManager.STATUS_SUCCESSFUL
                    ) {
                        //下载完成
                        bar.progress = 100
                        cancel()
                        timer.cancel()
                    }
                    val title =
                        cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE))
                    val url =
                        cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
                    val current =
                        cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                    val total =
                        cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                    val pro = current * 100 / total
                    val msg: Message = Message.obtain()
                    val bundle = Bundle()
                    bundle.putInt("pro", pro)
                    bundle.putString("name", title)
                    msg.data = bundle
                    handler.sendMessage(msg)
                }
                cursor?.close()
            }
        }
        timer.schedule(task, 0, 1000)

 

 类似资料: