• Android完整的下载实例


    1)新建一个dowmloadfile的项目

    2)在app/build中添加Okhttp的依赖

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        compile 'com.android.support:appcompat-v7:24.2.1'
        testCompile 'junit:junit:4.12'
        compile 'com.squareup.okhttp3:okhttp:3.4.1'//添加依赖
    }

    3)定义一个回掉接口DownloadListener 用于事件的监听

    public interface DownloadListener {
        void onProgress(int progress);//通知当前下载进度
        void onSuccess();//通知下载成功
        void onFiled();//通知下载失败
        void onPaused();//下载暂停
        void inCanceled();//下载取消
    }

    4)使用来实现下载

    package com.example.dowmloadfile.Myclass;
    
    import android.os.AsyncTask;
    import android.os.Environment;
    
    
    import com.example.dowmloadfile.imp.DownloadListener;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    
    /**
     * Created by 海绵宝宝 on 2019/5/13.
     */
    /**三个参数第一个为需要传入给后台的数据类型,第二个是进度显示类型,第三个为使用Integer作为反馈结果类型**/
    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 downloadListener;
    
        private boolean isCanceled=false;
    
        private boolean isPaused=false;
    
        private int lastProgress;
        //通过DownLoadTask回调下载状态
        public DownLoadTask(DownloadListener listener){
            downloadListener=listener;
        }
        @Override//后台执行具体的下载逻辑
        protected Integer doInBackground(String... params) {
            InputStream is=null;
            RandomAccessFile savedFile=null;
            File file=null;
            try{
                long downloadLength=0;
                String downloadUrl=params[0];
                String fileName=downloadUrl.substring(downloadUrl.lastIndexOf("/"));//解析出下载的文件名
                String derectory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();//获取本地的下载文件夹的路径
                file=new File(derectory+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();//head用于告诉服务器我们从那个字节开始下载
                Response response=client.newCall(request).execute();
                if (response!=null){
                    is=response.body().byteStream();
                    savedFile=new RandomAccessFile(file,"rw");
                    savedFile.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;
                            savedFile.write(b,0,len);
                            int progress=(int)((total+downloadLength)*100/contentLength);
                            publishProgress(progress);
                        }
                    }
                    response.body().close();
                    return TYPE_SUCCESS;
                };
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                try {
                    if (is!=null){
                        is.close();
                    }else if (savedFile!=null){
                        savedFile.close();
                    }else if (isCanceled&&file!=null){
                        file.delete();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            return TYPE_FAILED;
        }
    
        @Override//用于比较下载进度然后使用onProgress来更改下载进度的通知
        protected void onProgressUpdate(Integer... values) {
            int progress=values[0];
            if (progress>lastProgress){
                downloadListener.onProgress(progress);
                lastProgress=progress;
            }
        }
    
        @Override//根据传入的参数进行回调
        protected void onPostExecute(Integer integer) {
            switch (integer) {
                case TYPE_SUCCESS:
                    downloadListener.onSuccess();
                    break;
                case TYPE_FAILED:
                    downloadListener.onFiled();
                    break;
                case TYPE_PAUSED:
                    downloadListener.onPaused();
                    break;
                case TYPE_CANCELED:
                    downloadListener.inCanceled();
                default:
                    break;
            };
        }
        public void pauseDownload(){
            isPaused=true;
        }
        public void cancelDownload(){
            isCanceled=true;
        }
    
        //获取需要下载的文件长度
        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;
        }
    
    }

    5)为了保证下载可以一直运行我们需要创建一个服务

    package com.example.dowmloadfile.Myservice;
    
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.content.Intent;
    import android.graphics.BitmapFactory;
    import android.os.Binder;
    import android.os.Environment;
    import android.os.IBinder;
    import android.support.v4.app.NotificationCompat;
    import android.widget.Toast;
    
    import com.example.dowmloadfile.MainActivity;
    import com.example.dowmloadfile.Myclass.DownLoadTask;
    import com.example.dowmloadfile.R;
    import com.example.dowmloadfile.imp.DownloadListener;
    
    import java.io.File;
    
    public class DownloadService extends Service {
        private DownLoadTask downLoadTask;
        private String downloadUrl;
        //创建一个DownloadListener并实现其中的方法
        private DownloadListener downloadListener=new DownloadListener() {
            @Override//以通知的方式显示进度条
            public void onProgress(int progress) {
                //使用getNotificationManager函数构建一个用于显示下载进度的通知
                //使用notify去触发这个通知
                getNotificationManager().notify(1,getNotification("Download...",progress));
            }
    
            @Override
            public void onSuccess() {
                downLoadTask=null;
                //关闭前台服务通知
                stopForeground(true);
                getNotificationManager().notify(1,getNotification("download succeed",-1));
                Toast.makeText(DownloadService.this,"Download Succeed",Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void onFiled() {
                downLoadTask=null;
                //关闭前台服务通知
                stopForeground(true);
                getNotificationManager().notify(1,getNotification("download filed",-1));
                Toast.makeText(DownloadService.this,"Download failed",Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void onPaused() {
                downLoadTask=null;
                Toast.makeText(DownloadService.this,"Download Paused",Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void inCanceled() {
                downLoadTask=null;
                //关闭前台服务通知
                stopForeground(true);
                Toast.makeText(DownloadService.this,"Download canceled",Toast.LENGTH_LONG).show();
            }
        };
    
        private DownloadBinder mBinder=new DownloadBinder();
    
    
    
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            return mBinder;
        }
        //用于使服务可以和活动通信
        public class DownloadBinder extends Binder{
            public void startDownload(String url){
                if(downLoadTask==null){
                    downloadUrl=url;
                    downLoadTask=new DownLoadTask(downloadListener);
                    //使用execute开启下载
                    downLoadTask.execute(downloadUrl);
                    //startForeground使服务成为一个前台服务以创建持续运行的通知
                    startForeground(1,getNotification("download...",0));
                    Toast.makeText(DownloadService.this,"Download",Toast.LENGTH_LONG).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_LONG).show();
                    }
                }
            }
        }
    
        private NotificationManager getNotificationManager(){
            return (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        }
        private Notification getNotification(String title,int progress){
            Intent intent=new Intent(this, MainActivity.class);
            PendingIntent pi=PendingIntent.getActivity(this,0,intent,0);
            NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
            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();
        }
    }

    6)前台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:id="@+id/start"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="start download"/>
        <Button
            android:id="@+id/pause"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="start pause"/>
        <Button
            android:id="@+id/cancel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="start cancel"/>
    
    </LinearLayout>

    7)MainActivity.java中设置具体逻辑和按钮的触发事件

    package com.example.dowmloadfile;
    
    import android.Manifest;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.content.pm.PackageManager;
    import android.os.IBinder;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    import com.example.dowmloadfile.Myservice.DownloadService;
    
    public class MainActivity 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_main);
            Button start=(Button)findViewById(R.id.start);
            Button pause=(Button)findViewById(R.id.pause);
            Button cancel=(Button)findViewById(R.id.cancel);
            start.setOnClickListener(this);
            pause.setOnClickListener(this);
            cancel.setOnClickListener(this);
            Intent intent=new Intent(this, DownloadService.class);
            startService(intent);//启动服务保证服务一直运行
            bindService(intent,connection,BIND_AUTO_CREATE);//绑定服务保证数据在服务和活动中传递
            //申请运行时权限
            if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
            }
    
        }
    
        @Override
        public void onClick(View view){
            if(downloadBinder==null)
            {
                return;
            }
            switch (view.getId()){
                case R.id.start:
                    String url="http://icon.nipic.com/BannerPic/20190513/original/20190513111935_1.jpg";
                    downloadBinder.startDownload(url);
                    break;
                case R.id.pause:
                    downloadBinder.pauseDownload();
                    break;
                case R.id.cancel:
                    downloadBinder.cancelDownload();
                    break;
                default:
                    break;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(connection);
        }
    }

    8)申请权限

        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  • 相关阅读:
    面试准备专题——JVM,类编译,类加载,内存错误
    面试准备-基础知识总结
    J2EE异常问题总结
    Java工具类使用注意事项
    高性能大型网站性能优化基础
    Spring Boot 2 (三):Spring Boot 开源软件都有哪些?
    Spring Boot 2(一):【重磅】Spring Boot 2.0权威发布
    Spring Boot 2 (二):Spring Boot 2 尝鲜-动态 Banner
    MFC对话框使用CPrintDialog实现打印,指定打印机、后台打印
    stm32实现iap远程固件更新
  • 原文地址:https://www.cnblogs.com/837634902why/p/10861158.html
Copyright © 2020-2023  润新知