美文网首页
Android Service实践——下载示例

Android Service实践——下载示例

作者: dlihasa | 来源:发表于2019-01-02 23:37 被阅读12次
    前言

    本示例来自郭霖第一行代码第二版,因为其中涉及到了一些书中没有讲到的知识点,所以想在这篇中整体记录一下。

    (1)定义一个回调接口,用于对下载过程中的各种状态进行监听和回调

    public interface DownloadListener {
    
        void onProgress(int progress);
    
        void onSuccess();
    
        void onFail();
    
        void onPaused();
    
        void onCanceled();
    }
    

    (2)下载功能用AsyncTask来实现

    public class DownloadTask extends AsyncTask<String,Integer,Integer>{
    
        public static final int TYPE_SUCCESS = 0;
        public static final int TYPE_FAILED = 1;
        public static final int TYPE_PAUSED = 2;
        public static final int TYPE_CANCELED = 3;
    
        private DownloadListener listener;
        private boolean isCanceled = false;
        private boolean isPaused = false;
        private int lastProgress;
    
        public DownloadTask(DownloadListener listener){
            this.listener = listener;
        }
    
        @Override
        protected Integer doInBackground(String... params) {
            InputStream is = null;
            RandomAccessFile saveFile = null;
            File file = null;
            try {
                long downloadLength = 0;
                String downloadUrl = params[0];
                String filename = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
                String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
                file = new File(directory + filename);
                if(file.exists()){
                    downloadLength = file.length();
                }
                long contentLength = getContentLength(downloadUrl);
                if(contentLength==0){
                    return TYPE_FAILED;
                }else if(contentLength == downloadLength){
                    return TYPE_SUCCESS;
                }
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        //断点下载,指定从哪个字节开始下载
                        .addHeader("RANGE","bytes="+downloadLength+"-")
                        .url(downloadUrl)
                        .build();
                Response response = client.newCall(request).execute();
                if(response != null){
                    is = response.body().byteStream();
                    saveFile = new RandomAccessFile(file,"rw");
                    saveFile.seek(downloadLength);//跳过已下载的字节
                    byte[] b = new byte[1024];
                    int total = 0;
                    int len;
                    while((len = is.read(b))!=-1){
                        if(isCanceled){
                            return TYPE_CANCELED;
                        }else if(isPaused){
                            return TYPE_PAUSED;
                        }else{
                            total += len;
                        }
                        saveFile.write(b,0,len);
                        //计算已经下载的百分比
                        int progress = (int)((total+downloadLength)*100/contentLength);
                        publishProgress(progress);
                    }
                    response.body().close();
                    return TYPE_SUCCESS;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                    if(saveFile!=null){
                        saveFile.close();
                    }
                    if(isCanceled&&file!=null){
                        file.delete();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return TYPE_FAILED;
        }
    
        @Override
        protected void onProgressUpdate(Integer... params) {
            int progress = params[0];
            if(progress>lastProgress){
                listener.onProgress(progress);
                lastProgress = progress;
            }
        }
    
        @Override
        protected void onPostExecute(Integer status) {
            switch (status){
                case TYPE_SUCCESS:
                    listener.onSuccess();
                    break;
                case TYPE_FAILED:
                    listener.onFail();
                    break;
                case TYPE_PAUSED:
                    listener.onPaused();
                    break;
                case TYPE_CANCELED:
                    listener.onCanceled();
                    break;
                default:
                    break;
    
            }
        }
    
        public void pauseDownload(){
            isPaused = true;
        }
    
        public void cancelDownload(){
            isCanceled = true;
        }
    
        /**
         * 获取待下载文件的总长度
         * @param downloadUrl
         * @return
         * @throws IOException
         */
        private long getContentLength(String downloadUrl) throws IOException{
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(downloadUrl)
                    .build();
            Response response = client.newCall(request).execute();
            if(response!=null&&response.isSuccessful()){
                long contentLength = response.body().contentLength();
                response.close();
                return contentLength;
            }
            return 0;
        }
    }
    

    (1)AsyncTask中的3个泛型参数,第一个指定为String,表示在执行AsyncTask的时候需要传入一个字符串参数给后台任务;第二个指定为Integer,表示使用整型数据来作为进度显示单位;第三个指定为Integer,则表示使用整形数据来反馈执行结果。
    (2)RandomAccessFile可以查看(https://www.cnblogs.com/baoliyan/p/6225842.html)(https://www.cnblogs.com/zuochengsi-9/p/6485737.html
    (3)java获取文件大小可以参考(https://blog.csdn.net/chaijunkun/article/details/22387305
    (4)是时候弄清楚getExternalStorageDirectory()和getExternalFilesDir()的区别(https://blog.csdn.net/nugongahou110/article/details/48154859

    (3)为了保证DownloadTask可以一直在后台运行,创建一个下载的服务

    public class DownloadService extends Service {
    
        private DownloadTask downloadTask;
        private String downloadUrl;
        private DownloadBinder mBinder = new DownloadBinder();
        private DownloadListener listener = new DownloadListener() {
            @Override
            public void onProgress(int progress) {
                getNotificationManager().notify(1,getNotification("Downloading...",progress));
            }
    
            @Override
            public void onSuccess() {
                downloadTask = null;
                //下载成功关闭前台服务通知,并创建一个下载成功的通知
                stopForeground(true);
                getNotificationManager().notify(1,getNotification("Download Success",-1));
                Toast.makeText(DownloadService.this,"DownloadSuccess",Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onFail() {
                downloadTask = null;
                //下载失败关闭前台服务通知,并创建一个下载失败的通知
                stopForeground(true);
                getNotificationManager().notify(1,getNotification("Download Failed",-1));
                Toast.makeText(DownloadService.this,"DownloadFailed",Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onPaused() {
                downloadTask = null;
                Toast.makeText(DownloadService.this,"DownloadPaused",Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onCanceled() {
                downloadTask = null;
                stopForeground(true);
                Toast.makeText(DownloadService.this,"DownloadCancel",Toast.LENGTH_SHORT).show();
            }
        };
    
    
        public DownloadService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        class DownloadBinder extends Binder{
    
            public void startDownload(String url){
                if(downloadTask == null){
                    downloadUrl = url;
                    downloadTask = new DownloadTask(listener);
                    downloadTask.execute(downloadUrl);
                    startForeground(1,getNotification("Downloading...",0));
                    Toast.makeText(DownloadService.this,"Downloading...",Toast.LENGTH_SHORT).show();
                }
            }
    
            public void pauseDownload(){
                if(downloadTask!=null){
                    downloadTask.pauseDownload();
                }
            }
    
            public void cancelDownload(){
                if(downloadTask!=null){
                    downloadTask.cancelDownload();
                }else{
                    if(downloadUrl!=null){
                        String filename = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
                        String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
                        File file = new File(directory + filename);
                        if(file.exists()){
                            file.delete();
                        }
                        getNotificationManager().cancel(1);
                        stopForeground(true);
                        Toast.makeText(DownloadService.this,"Canceled...",Toast.LENGTH_SHORT).show();
                    }
                }
            }
    
        }
    
        private NotificationManager getNotificationManager(){
            return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        }
    
        private Notification getNotification(String title,int progress){
            Intent intent = new Intent(this, DownloadActivity.class);
            PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"007");
            builder.setSmallIcon(R.mipmap.ic_launcher);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
            builder.setContentIntent(pi);
            builder.setContentTitle(title);
            if(progress>0){
                builder.setContentText(progress+"%");
                builder.setProgress(100,progress,false);
            }
            return builder.build();
        }
    }
    

    (4)在activity中调用

    public class DownloadActivity extends AppCompatActivity implements View.OnClickListener{
    
        private DownloadService.DownloadBinder downloadBinder;
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                downloadBinder = (DownloadService.DownloadBinder) service;
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_download);
            Button startDownload = findViewById(R.id.start_download);
            Button pauseDownload = findViewById(R.id.pause_download);
            Button cancelDownload = findViewById(R.id.cancel_download);
            startDownload.setOnClickListener(this);
            pauseDownload.setOnClickListener(this);
            cancelDownload.setOnClickListener(this);
            Intent intent = new Intent(this,DownloadService.class);
            bindService(intent,connection,BIND_AUTO_CREATE);
            if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
            }
        }
    
        @Override
        public void onClick(View v) {
            if(downloadBinder==null){
                return;
            }
            switch (v.getId()){
                case R.id.start_download:
    //                String url = "https://raw.githubusercontent.com/guolindev/eclipse/master/eclipse-inst-win64.exe";
                    String url = "http://dubapkg.cmcmcdn.com/duba/166/kinst_166_f13_k0063.exe";
                    downloadBinder.startDownload(url);
                    break;
                case R.id.pause_download:
                    downloadBinder.pauseDownload();
                    break;
                case R.id.cancel_download:
                    downloadBinder.cancelDownload();
                    break;
                default:
                    break;
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode){
                case 1:
                    if(grantResults.length>0&&grantResults[0]!=PackageManager.PERMISSION_GRANTED){
                        Toast.makeText(this,"拒绝权限将无法使用程序",Toast.LENGTH_SHORT).show();
                        finish();
                    }
                    break;
                 default:
                     break;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(connection);
        }
    }
    

    相关文章

      网友评论

          本文标题:Android Service实践——下载示例

          本文链接:https://www.haomeiwen.com/subject/akdtrqtx.html