• 环境
  • 项目结构
  • 演示下载
  • 参考资料

本文是 github 上 Trinea-Android-commonTrinea-Android-Demo 项目的一部分,将下载部分分离出来,看看如何实现。(不知道此人学了多久,Android 水平不低~ 貌似年龄跟我差不多~Android 演示 DownloadManager——Android 下载 apk 包并安装

假设,现在有个下载 apk 包的需求,你大概能想到什么?

  • 下载本身;
  • 下载进度;
  • 期间还能取消;
  • 由于网络不好或中断,下载失败,还要能重试;
  • 因为下载的是 apk,下载完还要能提示安装更好,而且,很多手机管理 app,还能静默安装;
  • 还能在手机通知栏看到下载提示;
  • 这些就涉及到 android.app.DownloadManagerandroid.content.BroadcastReceiverandroid.os.Handler

自己下载 Demo 调试一下~

下载 Demo

更多 Demo

环境


  • Windows 2008 R2 64 位
  • Eclipse ADT V22.6.2,Android 4.4.2(API 19)
  • SAMSUNG GT-8618,Android OS 4.1.2

项目结构


Android 演示 DownloadManager——Android 下载 apk 包并安装

图 1 项目结构

Android 演示 DownloadManager——Android 下载 apk 包并安装

图 2 主程序

Android 演示 DownloadManager——Android 下载 apk 包并安装

图 3 下载

(注意:顶部通知栏,是有下载图标的~)

package com.example.download.ui;
 
import java.io.File;
import java.text.DecimalFormat;
import com.example.download.R;
import com.example.download.utils.DownloadManagerPro;
import com.example.download.utils.PreferencesUtils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
 
/**
 * DownloadManagerDemo
 * 
 */
public class DownloadManagerDemo extends Activity {
 
    public static final String DOWNLOAD_FOLDER_NAME = "Trinea";
    public static final String DOWNLOAD_FILE_NAME = "MeiLiShuo.apk";
 
    public static final String APK_URL = "http://img.meilishuo.net/css/images/AndroidShare/Meilishuo_3.6.1_10006.apk";
    public static final String KEY_NAME_DOWNLOAD_ID = "downloadId";
 
    private Button downloadButton;
    private ProgressBar downloadProgress;
    private TextView downloadTip;
    private TextView downloadSize;
    private TextView downloadPrecent;
    private Button downloadCancel;
 
    private DownloadManager downloadManager;
    private DownloadManagerPro downloadManagerPro;
    private long downloadId = 0;
 
    private MyHandler handler;
 
    private DownloadChangeObserver downloadObserver;
    private CompleteReceiver completeReceiver;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.download_manager_demo);
        
        handler = new MyHandler();
        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        downloadManagerPro = new DownloadManagerPro(downloadManager);
 
        // see android mainfest.xml, 
        // accept minetype of cn.trinea.download.file
        Intent intent = getIntent();
        if (intent != null) {
            /**
             * below android 4.2, intent.getDataString() is
             * file:///storage/sdcard1/Trinea/MeLiShuo.apk<br/>
             * equal or above 4.2 intent.getDataString() is
             * content://media/external/file/29669
             */
            Uri data = intent.getData();
            if (data != null) {
                Toast.makeText(getApplicationContext(), data.toString(), Toast.LENGTH_LONG)
                        .show();
            }
        }
 
        initView();
        initData();
 
        downloadObserver = new DownloadChangeObserver();
        completeReceiver = new CompleteReceiver();
        /** register download success broadcast **/
        registerReceiver(completeReceiver, new IntentFilter(
                DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        /** observer download change **/
        getContentResolver().registerContentObserver(
                DownloadManagerPro.CONTENT_URI, true, downloadObserver);
        updateView();
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        getContentResolver().unregisterContentObserver(downloadObserver);
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(completeReceiver);
    }
 
    private void initView() {
        downloadButton = (Button) findViewById(R.id.download_button);
        downloadCancel = (Button) findViewById(R.id.download_cancel);
        downloadProgress = (ProgressBar) findViewById(R.id.download_progress);
        downloadTip = (TextView) findViewById(R.id.download_tip);
        downloadTip
                .setText(getString(R.string.tip_download_file)
                        + Environment
                                .getExternalStoragePublicDirectory(DOWNLOAD_FOLDER_NAME));
        downloadSize = (TextView) findViewById(R.id.download_size);
        downloadPrecent = (TextView) findViewById(R.id.download_precent);
    }
 
    private void initData() {
        /**
         * get download id from preferences.<br/>
         * if download id bigger than 0, means it has been downloaded, then
         * query status and show right text;
         */
        downloadId = PreferencesUtils.getLong(getApplicationContext(), KEY_NAME_DOWNLOAD_ID);
        updateView();
        downloadButton.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
                File folder = new File(DOWNLOAD_FOLDER_NAME);
                if (!folder.exists() || !folder.isDirectory()) {
                    folder.mkdirs();
                }
 
                DownloadManager.Request request = new DownloadManager.Request(
                        Uri.parse(APK_URL));
                request.setDestinationInExternalPublicDir(DOWNLOAD_FOLDER_NAME,
                        DOWNLOAD_FILE_NAME);
                request.setTitle(getString(R.string.download_notification_title));
                request.setDescription("meilishuo desc");
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                request.setVisibleInDownloadsUi(false);
                // request.allowScanningByMediaScanner();
                // request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
                // request.setShowRunningNotification(false);
                // request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
                request.setMimeType("application/cn.trinea.download.file");
                
                downloadId = downloadManager.enqueue(request);
                /** save download id to preferences **/
                PreferencesUtils.putLong(getApplicationContext(), KEY_NAME_DOWNLOAD_ID,
                        downloadId);
                updateView();
            }
        });
        downloadCancel.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
                downloadManager.remove(downloadId);
                updateView();
            }
        });
    }
 
    /**
     * install app
     * 
     * @param context
     * @param filePath
     * @return whether apk exist
     */
    public static boolean install(Context context, String filePath) {
        Intent i = new Intent(Intent.ACTION_VIEW);
        File file = new File(filePath);
        if (file != null && file.length() > 0 && file.exists() && file.isFile()) {
            i.setDataAndType(Uri.parse("file://" + filePath),
                    "application/vnd.android.package-archive");
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
            return true;
        }
        return false;
    }
 
    class DownloadChangeObserver extends ContentObserver {
 
        public DownloadChangeObserver() {
            super(handler);
        }
 
        @Override
        public void onChange(boolean selfChange) {
            updateView();
        }
 
    }
 
    class CompleteReceiver extends BroadcastReceiver {
 
        @Override
        public void onReceive(Context context, Intent intent) {
            /**
             * get the id of download which have download success, if the id is
             * my id and it's status is successful, then install it
             **/
            long completeDownloadId = intent.getLongExtra(
                    DownloadManager.EXTRA_DOWNLOAD_ID, -1);
            if (completeDownloadId == downloadId) {
                initData();
                updateView();
                // if download successful, install apk
                if (downloadManagerPro.getStatusById(downloadId) == DownloadManager.STATUS_SUCCESSFUL) {
                    String apkFilePath = new StringBuilder(Environment
                            .getExternalStorageDirectory().getAbsolutePath())
                            .append(File.separator)
                            .append(DOWNLOAD_FOLDER_NAME)
                            .append(File.separator).append(DOWNLOAD_FILE_NAME)
                            .toString();
                    install(context, apkFilePath);
                }
            }
        }
    };
 
    public void updateView() {
        int[] bytesAndStatus = downloadManagerPro.getBytesAndStatus(downloadId);
        handler.sendMessage(handler.obtainMessage(0, bytesAndStatus[0],
                bytesAndStatus[1], bytesAndStatus[2]));
    }
 
    @SuppressLint("HandlerLeak")
    private class MyHandler extends Handler {
 
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
 
            switch (msg.what) {
            case 0:
                int status = (Integer) msg.obj;
                if (isDownloading(status)) {
                    downloadProgress.setVisibility(View.VISIBLE);
                    downloadProgress.setMax(0);
                    downloadProgress.setProgress(0);
                    downloadButton.setVisibility(View.GONE);
                    downloadSize.setVisibility(View.VISIBLE);
                    downloadPrecent.setVisibility(View.VISIBLE);
                    downloadCancel.setVisibility(View.VISIBLE);
 
                    if (msg.arg2 < 0) {
                        downloadProgress.setIndeterminate(true);
                        downloadPrecent.setText("0%");
                        downloadSize.setText("0M/0M");
                    } else {
                        downloadProgress.setIndeterminate(false);
                        downloadProgress.setMax(msg.arg2);
                        downloadProgress.setProgress(msg.arg1);
                        downloadPrecent.setText(getNotiPercent(msg.arg1,
                                msg.arg2));
                        downloadSize.setText(getAppSize(msg.arg1) + "/"
                                + getAppSize(msg.arg2));
                    }
                } else {
                    downloadProgress.setVisibility(View.GONE);
                    downloadProgress.setMax(0);
                    downloadProgress.setProgress(0);
                    downloadButton.setVisibility(View.VISIBLE);
                    downloadSize.setVisibility(View.GONE);
                    downloadPrecent.setVisibility(View.GONE);
                    downloadCancel.setVisibility(View.GONE);
 
                    if (status == DownloadManager.STATUS_FAILED) {
                        downloadButton
                                .setText(getString(R.string.app_status_download_fail));
                    } else if (status == DownloadManager.STATUS_SUCCESSFUL) {
                        downloadButton
                                .setText(getString(R.string.app_status_downloaded));
                    } else {
                        downloadButton
                                .setText(getString(R.string.app_status_download));
                    }
                }
                break;
            }
        }
    }
 
    static final DecimalFormat DOUBLE_DECIMAL_FORMAT = new DecimalFormat("0.##");
 
    public static final int MB_2_BYTE = 1024 * 1024;
    public static final int KB_2_BYTE = 1024;
 
    /**
     * @param size
     * @return
     */
    public static CharSequence getAppSize(long size) {
        if (size <= 0) {
            return "0M";
        }
 
        if (size >= MB_2_BYTE) {
            return new StringBuilder(16).append(
                    DOUBLE_DECIMAL_FORMAT.format((double) size / MB_2_BYTE))
                    .append("M");
        } else if (size >= KB_2_BYTE) {
            return new StringBuilder(16).append(
                    DOUBLE_DECIMAL_FORMAT.format((double) size / KB_2_BYTE))
                    .append("K");
        } else {
            return size + "B";
        }
    }
 
    public static String getNotiPercent(long progress, long max) {
        int rate = 0;
        if (progress <= 0 || max <= 0) {
            rate = 0;
        } else if (progress > max) {
            rate = 100;
        } else {
            rate = (int) ((double) progress / max * 100);
        }
        return new StringBuilder(16).append(rate).append("%").toString();
    }
 
    public static boolean isDownloading(int downloadManagerStatus) {
        return downloadManagerStatus == DownloadManager.STATUS_RUNNING
                || downloadManagerStatus == DownloadManager.STATUS_PAUSED
                || downloadManagerStatus == DownloadManager.STATUS_PENDING;
    }
}

相关文章: