第一行代码 10.6服务:完整版的下载实例

适配最新版的安卓11版本,针对原书中的已经过时的方法做了修改:

1.原:String directory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
修改后:String directory =context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath();

2.原:Notification notification=NotificationCompat.Builder(this)

修改后://增加渠道
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
         NotificationChannel notificationChannel = new NotificationChannel("1","my_channel", NotificationManager.IMPORTANCE_DEFAULT);
         manager.createNotificationChannel(notificationChannel);
     }
//针对书上过时无法使用的方法进行修改
     Notification notification = new NotificationCompat.Builder(getBaseContext(), "message")
             .setSmallIcon(R.mipmap.ic_launcher2)
             .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher2))
             .setContentIntent(pi)
             .setChannelId("1")  //要和渠道中的id一致
             .setContentTitle(title)
             .setContentText(progress +"%")
             .setProgress(100,progress,false)
             .build();

     return notification;
 }

且通知已经加了渠道可以正常使用

1.DownloadListener接口

/**
 * @anthor liu
 * @createTime 2021/12/9 10:21
 * @decription
 */
public interface DownloadListener {
    void onProgress(int progress);//通知当前的下载进度
    void onSuccess();//通知下载成功事件
    void onFailed();//通知下载失败
    void onPause();//通知下载暂停
    void onCanceled();//通知下载取消
}

2.DownloadTask:下载的任务逻辑


/**
 * @anthor liu
 * @createTime 2021/12/9 10:25
 * @decription  参数1:传入字符串给后台任务
 *  参数2.使用整型数据作为显示进度的单位
 *  参数3.使用整型数据来反馈执行结果
 */
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;
Context context;
    private DownloadListener listener;
    private boolean isCanceled=false;
    private boolean isPaused=false;
    private int lastProgress;

    public DownloadTask(DownloadListener listener,Context context){
        this.listener=listener;
        this.context=context;
    }


    /*doInBackground方法 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中,执行具体的下载任务。
     * 这里将主要负责执行那些很耗时的后台处理工作。可以调用 publishProgress方法来更新实时的任务进度。
     * 该方法是抽象方法,子类必须实现。
*/
    @Override
    protected Integer doInBackground(String... params) {
        InputStream is=null;
        RandomAccessFile savedFile = null;
        File file=null;
        try {
            long downloadedLength =0;//记录已下载的文件长度
            String downloadUrl=params[0];
            String fileName=downloadUrl.substring(downloadUrl.lastIndexOf("/"));
            String directory =context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath();

            //String directory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
            file=new File(directory + fileName);
            Log.e("xx", file.getAbsolutePath());
            //Log.e("xx", String.valueOf(file.exists()));
            if(file.exists()){
                downloadedLength=file.length();
            }
            long contentLength=getContentLength(downloadUrl);
            if(contentLength==0){
                Log.d("xx","文件有问题");
                return TYPE_FAILED;
            }else if (contentLength==downloadedLength){ //已下载字节和文件总字节相等,说明已经下载完成
                return  TYPE_SUCCESS;
            }
            OkHttpClient client=new OkHttpClient();
            Request request=new Request.Builder()
                    .addHeader("RANGE","bytes=" + downloadedLength + "-")
                    .url(downloadUrl)
                    .build();
            Response response=client.newCall(request).execute();
            if(response!=null){
                is=response.body().byteStream();
                savedFile = new RandomAccessFile(file,"rw");
                savedFile.seek(downloadedLength);  //跳过已下载的字节
                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 + downloadedLength) *100/contentLength);
                        publishProgress(progress);
                    }
                }
                response.body().close();
                return TYPE_SUCCESS;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if(is !=null){
                    is.close();
                }
                if (savedFile !=null){
                    savedFile.close();
                }
                if(isCanceled && file!=null){
                    file.delete();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return TYPE_FAILED;
    }

    /**
     * 当在后台任务中调用publishProgress方法后,该方法被调用
     * 界面上更新下载进度
     * @param values
     */

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        int progress=values[0];
        if(progress>lastProgress){
            listener.onProgress(progress);
            lastProgress=progress;
        }
    }

    /**
     * 当后台任务执行完毕并通过return语句进行返回时,返回的数据会作为参数传递,统治下在结果
     * @param status
     */
    @Override
    protected void onPostExecute(Integer status) {
        super.onPostExecute(status);
        switch (status) {
            case TYPE_SUCCESS:
                listener.onSuccess();
                break;
                case TYPE_FAILED:
                listener.onFailed();
                break;
                case TYPE_PAUSED:
                listener.onPause();
                break;
                case TYPE_CANCELED:
                listener.onCanceled();
                break;
            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.body().close();
                return contentLength;

            }
            return 0;
    }
}

3.DownloadService

public class DownloadService extends Service {

    private DownloadTask downloadTask;
   // Context context;
    private String downloadUrl;
     private DownloadListener listener=new DownloadListener() {
         @Override
         public void onProgress(int progress) {
             getNotificationManager().notify(1,getNotification("Download ...",progress));
             Log.d("DownloadService","Download ...");
         }


         @Override
         public void onSuccess() {
             downloadTask=null;
             //下载成功时将前台服务通知关闭,并创建一个下载成功的通知
             stopForeground(true);
             getNotificationManager().notify(1,getNotification("Download Success",-1));
             Toast.makeText(DownloadService.this,"Download Success",Toast.LENGTH_SHORT).show();
         }

         @Override
         public void onFailed() {
             downloadTask=null;
             stopForeground(true);
             getNotificationManager().notify(1,getNotification("Download Failed",-1));
             Toast.makeText(DownloadService.this,"Download Failed",Toast.LENGTH_SHORT).show();
         }

         @Override
         public void onPause() {
             downloadTask=null;
             Toast.makeText(DownloadService.this,"Paused",Toast.LENGTH_SHORT).show();
         }

         @Override
         public void onCanceled() {
             downloadTask=null;
             stopForeground(true);
             Toast.makeText(DownloadService.this,"Canceled",Toast.LENGTH_SHORT).show();
         }
     };

     private DownLoadBinder mBinder=new DownLoadBinder();
    public DownloadService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
       // throw new UnsupportedOperationException("Not yet implemented");
        return mBinder;
    }

    class DownLoadBinder extends Binder {
        //开始下载
        public void startDownload(String url){
            if(downloadTask==null){
                downloadUrl=url;
                downloadTask=new DownloadTask(listener,getBaseContext());
                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();
            }
           if(downloadUrl!=null){
               //取消下载时将文件删除,并关闭通知
               String fileName=downloadUrl.substring(downloadUrl.lastIndexOf("/"));
               String directory =getBaseContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath();
               //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, MainActivity.class);
     PendingIntent pi=PendingIntent.getActivity(this,0,intent,0);
     //NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
     NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//增加渠道
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
         NotificationChannel notificationChannel = new NotificationChannel("1","my_channel", NotificationManager.IMPORTANCE_DEFAULT);
         manager.createNotificationChannel(notificationChannel);
     }
//针对书上过时无法使用的方法进行修改
     Notification notification = new NotificationCompat.Builder(getBaseContext(), "message")
             .setSmallIcon(R.mipmap.ic_launcher2)
             .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher2))
             .setContentIntent(pi)
             .setChannelId("1")  //要和渠道中的id一致
             .setContentTitle(title)
             .setContentText(progress +"%")
             .setProgress(100,progress,false)
             .build();

     return notification;
 }
}

4.布局文件

<?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_download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Download"/>
    <Button
        android:id="@+id/pause_download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Pause Download"/>
    <Button
        android:id="@+id/cancel_download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Cancel Download"/>


</LinearLayout>

5.activity活动类

public class Activity10_2 extends AppCompatActivity implements View.OnClickListener {
    private DownloadService.DownLoadBinder downloadBinder;
    private ServiceConnection connection = new ServiceConnection() {


        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (DownloadService.DownLoadBinder) service;//向下转型得到DownLoadBinder实例
        }
    };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity10_2);
            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);
            startService(intent);
            bindService(intent,connection,BIND_AUTO_CREATE);//
            if(ContextCompat.checkSelfPermission(Activity10_2.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(Activity10_2.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://img-s-msn-com.akamaized.net/tenant/amp/entityid/BB193Wn2.img?h=530&w=799&m=6&q=60&o=f&l=f";
                    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, String[] permissions, 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:
        }
    }

    @Override
    protected void onDestroy() {//程序销毁前,进行解绑
        super.onDestroy();
        unbindService(connection);
    }

    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值