添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

上一篇博客整理了一下 HttpURLConnection断点下载文件的方法 。其实还有另外一种下载大文件的方法。就是通过DownloadManager来进行下载的,如果可以后台下载更新,那么用DownloadManager来下载更轻松一点。

先说我遇到的坑吧:
1,文件下载地址必须是https
2,文件下载地址不能有302等重定向下载操作

那么如果真的是有302的话,那么可以怎么绕过呢?

public interface OnCallback {
    void onUrl(String url);
public void fetchRealUrl(final String urlString, final OnCallback callback) {
    new AsyncTask<String, Boolean, Boolean>() {
        private String mUrl = "";
        @Override
        protected Boolean doInBackground(String... strings) {
            mUrl = urlString;
            HttpURLConnection con = null;
            try {
                URL url = new URL(mUrl);
                con = (HttpURLConnection) url.openConnection();
                con.setInstanceFollowRedirects(false);
                con.setConnectTimeout(1000);
                con.connect();
                int resCode = con.getResponseCode();
                if (resCode == HttpURLConnection.HTTP_SEE_OTHER
                        || resCode == HttpURLConnection.HTTP_MOVED_PERM
                        || resCode == HttpURLConnection.HTTP_MOVED_TEMP) {
                    String Location = con.getHeaderField("Location");
                    if (Location.startsWith("/")) {
                        Location = url.getProtocol() + "://" + url.getHost() + Location;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (con != null) con.disconnect();
            return true;
        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            callback.onUrl(mUrl);
    }.execute();

然后这里给一个简单的demo。参考官方文档

AndroidManifest.xml

<receiver
    android:name=".DownloadReceiver"
    android:exported="true"
    android:icon="@mipmap/ic_launcher">
    <intent-filter>
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
    </intent-filter>
</receiver>

DownloadReceiver.java

package org.yeshen.download;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class DownloadReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        Toast.makeText(context, "Download Completed, id:" + id, Toast.LENGTH_SHORT).show();

MainActivity.java

package org.yeshen.download;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.io.File;
public class MainActivity extends Activity {
    private DownloadReceiver onDownloadComplete = new DownloadReceiver();
    private DownloadManager downloadManager;
    private long downloadID;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
    @Override
    protected void onDestroy() {
        unregisterReceiver




    
(onDownloadComplete);
        super.onDestroy();
    public void onStart(View view) {
        File file = new File(getExternalFilesDir(null), "robots.txt");
        Log.d("Yeshen file path:", file.getAbsolutePath());
        if (file.exists()) {
            //noinspection ResultOfMethodCallIgnored
            file.delete();
        DownloadManager.Request request = new DownloadManager.Request(
                Uri.parse("http://yeshen.org/robots.txt"))
                .setTitle("Yeshen robots download")
                .setDescription("Downloading")
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
                .setDestinationUri(Uri.fromFile(file))
                .setAllowedOverRoaming(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            request.setRequiresCharging(false).setAllowedOverMetered(true);
        request.setShowRunningNotification(true);
        downloadID = downloadManager.enqueue(request);
        Toast.makeText(this, "pending,id:'" + downloadID, Toast.LENGTH_SHORT).show();
    public void onCheck(View view) {
        Cursor c = downloadManager.query(new DownloadManager.Query().setFilterById(downloadID));
        if (c == null) {
            Toast.makeText(this, "Download not found!", Toast.LENGTH_LONG).show();
        } else {
            c.moveToFirst();
            Log.d(getClass().getName(), "COLUMN_ID: " +
                    c.getLong(c.getColumnIndex(DownloadManager.COLUMN_ID)));
            Log.d(getClass().getName(), "COLUMN_BYTES_DOWNLOADED_SO_FAR: " +
                    c.getLong(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)));
            Log.d(getClass().getName(), "COLUMN_LAST_MODIFIED_TIMESTAMP: " +
                    c.getLong(c.getColumnIndex(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP)));
            Log.d(getClass().getName(), "COLUMN_LOCAL_URI: " +
                    c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)));
            Log.d(getClass().getName(), "COLUMN_STATUS: " +
                    c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)));
            Log.d(getClass().getName(), "COLUMN_REASON: " +
                    c.getInt(c.getColumnIndex(DownloadManager.COLUMN_REASON)));
            Toast.makeText(this, statusMessage(c), Toast.LENGTH_LONG).show();
    private String statusMessage(Cursor c) {
        switch (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
            case DownloadManager.STATUS_SUCCESSFUL:
                return = "Download complete!";
            default:
                return "";

代码量很少对不对,一两百行代码就搞定一个稳定的异步下载,比我之前唾沫横飞的写了几百行断点下载的代码容易多了,还可以检查下载的进度,还是异步任务,还不怕切后台,还可以重新下载,还可以设置下载的header,放一些cookie什么的。

有时候,为了偷懒,我们会把下载任务移交给浏览器去做,大概就是这样:

public void installByBrowser(@NonNull Context context,@NonNull String url) {
    final Uri uri = Uri.parse(url);
    final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    if (context instanceof Activity) {
        context.startActivity(intent);
    } else if (context instanceof Service) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);

浏览器是怎么处理的呢,当然也是调用DownloadManger去处理的呀。

再深问一句,DownloadManger的系统服务的代码在哪里呢?

代码在packages/provider/DownloadProvider中,它从content-provider中获取下载参数,然后开线程执行下载。点进去看具体的细节,思路把异步任务包装了发送到线程池中。

主要的下载逻辑在DownloadThread中,也是基于HttpURLConnection。看了一下细节,包装比较用心,而且支持开机启动下载,各个方面的细节考虑得确实比较周到。比我随手写的HttpURLConnection断点下载文件的方法,考虑的细节要多上许多。

要不要分析下DownloadProvider的代码?

我觉得没必要了(笑),代码都很简单。

.
.
.

没有更多了,玩~

上一篇博客整理了一下HttpURLConnection断点下载文件的方法。其实还有另外一种下载大文件的方法。就是通过DownloadManager来进行下载的,如果可以后台下载更新,那么用DownloadManager来下载更轻松一点。先说我遇到的坑吧:1,文件下载地址必须是https2,文件下载地址不能有302等重定向下载操作那么如果真的是有302的话,那么可以怎么绕过呢?public...
1、多线程介绍 用过迅雷的同学都知道,迅雷有个功能叫做多线程,还有一个叫离线下载,我们这里重点介绍一下多线程下载。多线程,顾名思义就是很多歌线程同时在运行,为什么要提出多线程这个概念呢?因为有时候一个线程下载太慢了。举个例子,比如小时候常做的数学题,一个人挖沟需要15天,那么两个人对着挖呢? 当然数学题上面两个人的效率是不一样的,我们这里把这个问题简化了一下,只是想大家明白,什么是多线程,
版本的升级和更新是一个线上App所必备的功能,App的升级安装包主要通过 应用商店 或者 应用内下载 两种方式获得,大部分app这两种方式都会具备,应用商店只需要上传对应平台审核通过即可,而应用内更新一般是通过以下几种方式: 1.集成第三方库如 appupdateX、bugly 的更新功能 2.手动实现 这里自己从网上找了一些资料,使用 Kotl
MP1中完成了cool语言的lexer和parser,除了支持cool的全部语法外,在基本要求之上还可以处理很多其他错误,例如feature和formal的大小写问题、if和while表达式的错误等等。 MP2中完成了cool编译器的后端,可以由AST生成llvm IR指令,实现的是MP2要求中的COOL语言子集,包括int和bool常量、算术和比较运算、let、if、while、赋值和除数为0的运行时错误处理。