zoukankan      html  css  js  c++  java
  • OkDownload项目实战

    本文介绍项目中引入okhttp-okgo开源框架里的OkDownload部分,实现了RecyclerView列表的下载功能.

    • 引入OKDownload

    需求不仅是要支持断点续传,而且还要支持队列下载和任务恢复,这样单单导入okgo的包是不够的,还需要额外导入下面这个okserver的包.然后在APPlication里初始化OkGo

    //初始化OkGo
    OkGo.getInstance().init(this);
    //设置下载路径
    OkDownload.getInstance().setFolder(Constants.DOWNLOAD_APK_PATH);
    • 单个任务的下载

    上篇博文已经介绍了三个任务下载的基本使用,现在这里直接粘贴代码

       GetRequest<File> request = OkGo.get(itemsBean.getUrl());
      DownloadTask task = OkDownload.request(itemsBean.getUrl(), request) .save().register(new ListDownloadListener(itemsBean.getUrl(), mHolder));
      task.start();

    根据下载url得到一个GetRequest对象,然后调用OkDownload的静态方法,把一个保证下载任务唯一性的key(String类型)和这个GetRequest对象传递进去就可以创建一个下载任务了.

    • 列表下载

    okdownload库中维护了一个由线程池控制的下载队列,可以通过下面这个方式来设定允许同时下载的任务数目(默认是3个)

    OkDownload.getInstance().getThreadPool().setCorePoolSize(2);

    然后就是状态控制了,我们都知道一个文件下载伴随有这几种状态

     public static final int NONE = 0;         //无状态
     public static final int WAITING = 1;      //等待
     public static final int LOADING = 2;      //下载中
     public static final int PAUSE = 3;        //暂停
     public static final int ERROR = 4;        //错误
     public static final int FINISH = 5;       //完成

    可以根据它提供的一个Progress的status,表示当前状态的字段,来更新UI,给用户反馈.

    于是,我们可以获取到当前item的任务之后,让下载的点击事件这样响应:

      Progress progress = task.progress;
                if (progress.status == Progress.LOADING || progress.status == Progress.PAUSE) {
                    flikerProgressBar.toggle();
                }
                switch (progress.status) {
                    case Progress.PAUSE:
                    case Progress.NONE:
                    case Progress.ERROR:
                        task.start();
                        break;
                    case Progress.LOADING:
                        task.pause();
                        break;
                    case Progress.FINISH:
                        if (ApkUtils.isAvailable(context, new File(progress.filePath))) {
                            ApkUtils.startAPP(context, ApkUtils.getPackageName(context, progress.filePath));
                        } else {
                            ApkUtils.install(context, new File(progress.filePath));
                        }
                        break;
                }
                refresh(progress);
    • 判断和获取指定tag的下载任务
      DownloadTask task;
                       
    if (!OkDownload.getInstance().hasTask(itemsBean.getUrl())) {
    GetRequest
    <File> request = OkGo.get(itemsBean.getUrl());
    task
    = OkDownload.request(itemsBean.getUrl(), request)
    .save().register(
    new ListDownloadListener(itemsBean.getUrl(), mHolder));
    }
    else {
    task
    = OkDownload.getInstance().getTask(itemsBean.getUrl());
    }

    如果下载队列里不包含当前tag的任务,通过OkDownload.getInstance().hasTask(String tag)判断,那么就对它新建一个下载任务,因为我们要对他进行下载操作.

    如果下载队列里已经包含当前任务,那么我们通过OkDownload.getInstance().getTask(String tag)方法来获取这个task;

    然后对这个task进行上面的步骤.

    如此,一个下载队列的功能就完成了.

    下面贴出完整代码

    public class BaseAppsDownloadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
        private List<AppBean.ResultBean.ItemsBean> mList;
        private LayoutInflater inflater;
        private Context context;
        private List<DownloadTask> values;
        private boolean comeFromRank;
    
        public BaseAppsDownloadAdapter(Context context, List<AppBean.ResultBean.ItemsBean> mList, boolean comeFromRank) {
            this.comeFromRank = comeFromRank;
            this.mList = mList;
            this.context = context;
            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }
    
        public void updateData() {
            //这里是将数据库的数据恢复
            values = OkDownload.restore(DownloadManager.getInstance().getAll());
            notifyDataSetChanged();
        }
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = inflater.inflate(R.layout.home_innovate_item, parent, false);
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (mList == null || mList.size() == 0) {
                return;
            }
            AppBean.ResultBean.ItemsBean itemsBean = mList.get(position);
            if (itemsBean == null) {
                return;
            }
            ViewHolder mHolder = (ViewHolder) holder;
            // 判断布局中是否需要显示排行
            if (comeFromRank) {
                mHolder.tv_rank.setVisibility(View.VISIBLE);
                mHolder.tv_rank.setText("" + (position + 1));
            } else {
                mHolder.tv_rank.setVisibility(View.GONE);
            }
            mHolder.bind(mHolder, itemsBean);
            mHolder.flikerProgressBar.setVisibility(View.INVISIBLE);
            mHolder.ib_download.setVisibility(View.VISIBLE);
            if (TextUtils.isEmpty(itemsBean.getUrl())) {
                return;
            }
            if (OkDownload.getInstance().hasTask(itemsBean.getUrl())) {
                DownloadTask task = OkDownload.getInstance().getTask(itemsBean.getUrl()).register(new ListDownloadListener(itemsBean.getUrl(), mHolder));
                mHolder.setTask(task);
                mHolder.setTag(itemsBean.getUrl());
                mHolder.flikerProgressBar.setVisibility(View.VISIBLE);
                mHolder.ib_download.setVisibility(View.INVISIBLE);
                mHolder.refresh(task.progress);
            } else {
                mHolder.flikerProgressBar.setVisibility(View.INVISIBLE);
                mHolder.ib_download.setVisibility(View.VISIBLE);
                mHolder.setTask(null);
                mHolder.setTag(null);
            }
        }
    
        public void notifySetDataListChanged(List<AppBean.ResultBean.ItemsBean> appsData) {
            mList = appsData;
            notifyDataSetChanged();
        }
    
        public void unRegister() {
            Map<String, DownloadTask> taskMap = OkDownload.getInstance().getTaskMap();
            for (DownloadTask task : taskMap.values()) {
                task.unRegister(task.progress.tag);
            }
        }
    
        @Override
        public int getItemCount() {
            return mList == null ? 0 : mList.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
            private final ImageView iv_icon;
            private final TextView tv_name;
            private final TextView tv_size;
            private final TextView tv_rank;
            private final TextView tv_des;
            private final TextView ib_download;
            private FlickerProgressBar flikerProgressBar;
            private DownloadTask task;
            private String tag;
    
            public ViewHolder(View itemView) {
                super(itemView);
                iv_icon = ((ImageView) itemView.findViewById(R.id.app_icon));
                tv_name = ((TextView) itemView.findViewById(R.id.tv_app_name));
                tv_size = ((TextView) itemView.findViewById(R.id.tv_app_size));
                tv_rank = ((TextView) itemView.findViewById(R.id.tv_app_rank));
                tv_des = ((TextView) itemView.findViewById(R.id.tv_app_des));
                ib_download = ((TextView) itemView.findViewById(R.id.ib_download));
                flikerProgressBar = ((FlickerProgressBar) itemView.findViewById(R.id.btn_progress));
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        context.startActivity(new Intent(context, AppDetailActivity.class)
                                .putExtra("appid", mList.get(getAdapterPosition()).getId())
                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                    }
                });
            }
    
            public void setTask(DownloadTask task) {
                this.task = task;
            }
    
            public void bind(final ViewHolder mHolder, final AppBean.ResultBean.ItemsBean itemsBean) {
                mHolder.tv_name.setText(itemsBean.getName());
                if (TextUtils.isEmpty(itemsBean.getImageUrl())) {
                    mHolder.iv_icon.setImageResource(R.mipmap.icon_default);
                } else {
                    Glide.with(context).load(itemsBean.getImageUrl()).placeholder(R.mipmap.icon_default).into(mHolder.iv_icon);
                }
                mHolder.tv_des.setText("" + itemsBean.getAbstractString());
                mHolder.tv_size.setText(FileUtil.bytes2kb(itemsBean.getSize()));
                mHolder.flikerProgressBar.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (TextUtils.isEmpty(itemsBean.getUrl())) {
                            Toast.makeText(v.getContext(), "下载链接不存在", Toast.LENGTH_SHORT).show();
                            return;
                        }
                        DownloadTask task;
                        if (!OkDownload.getInstance().hasTask(itemsBean.getUrl())) {
                            GetRequest<File> request = OkGo.get(itemsBean.getUrl());
                            task = OkDownload.request(itemsBean.getUrl(), request)
                                    .save().register(new ListDownloadListener(itemsBean.getUrl(), mHolder));
                        } else {
                            task = OkDownload.getInstance().getTask(itemsBean.getUrl());
                        }
                        mHolder.setTask(task);
                        mHolder.setTag(itemsBean.getUrl());
                        mHolder.start();
                    }
                });
            }
    
            public void refresh(Progress progress) {
                flikerProgressBar.setProgress((int) (progress.fraction * 100));
                switch (progress.status) {
                    case Progress.NONE:
                        flikerProgressBar.setText("下载");
                        break;
                    case Progress.PAUSE:
                        flikerProgressBar.setText("继续");
                        break;
                    case Progress.ERROR:
                        flikerProgressBar.setText("出错");
                        break;
                    case Progress.WAITING:
                        flikerProgressBar.setText("等待");
                        break;
                    case Progress.FINISH:
                        if (ApkUtils.isAppInstalled(context, ApkUtils.getPackageName(context, progress.filePath))) {
                            flikerProgressBar.setText("打开");
                        } else {
                            flikerProgressBar.setText("安装");
                        }
                        break;
                    case Progress.LOADING:
                        flikerProgressBar.setText((int) (progress.fraction * 100 + 0.5f) + "%");
                        break;
                }
            }
    
            public void start() {
                Progress progress = task.progress;
                if (progress.status == Progress.LOADING || progress.status == Progress.PAUSE) {
                    flikerProgressBar.toggle();
                }
                switch (progress.status) {
                    case Progress.PAUSE:
                    case Progress.NONE:
                    case Progress.ERROR:
                        task.start();
                        break;
                    case Progress.LOADING:
                        task.pause();
                        break;
                    case Progress.FINISH:
                        if (ApkUtils.isAvailable(context, new File(progress.filePath))) {
                            ApkUtils.startAPP(context, ApkUtils.getPackageName(context, progress.filePath));
                        } else {
                            ApkUtils.install(context, new File(progress.filePath));
                        }
                        break;
                }
                refresh(progress);
            }
    
            public void setTag(String tag) {
                this.tag = tag;
            }
    
            public String getTag() {
                return tag;
            }
        }
    
        private class ListDownloadListener extends DownloadListener {
    
            private ViewHolder holder;
    
            ListDownloadListener(Object tag, ViewHolder holder) {
                super(tag);
                this.holder = holder;
            }
    
            @Override
            public void onStart(Progress progress) {
            }
    
            @Override
            public void onProgress(Progress progress) {
                if (tag == holder.getTag()) {
                    holder.refresh(progress);
                }
            }
    
            @Override
            public void onError(Progress progress) {
                Throwable throwable = progress.exception;
                if (throwable != null) throwable.printStackTrace();
            }
    
            @Override
            public void onFinish(File file, Progress progress) {
                Toast.makeText(context, "下载完成:" + progress.filePath, Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onRemove(Progress progress) {
            }
        }

     上面的代码,之所以可以有效的避免RecyclerView滚动item布局混乱的问题.是因为我们对每一个item的各项数据都做了赋值操作.

     更新下载进度的ListDownloadListener 只与该任务的tag有关,而tag又是itemBean.getUrl() , 所以只要下载链接唯一,那么这个监听是不会响应到别的iteam上的.

     

     
  • 相关阅读:
    MongoDB简单使用
    mongodb安装部署
    分布式通信-序列化
    分布式通信协议
    分布式概念
    springboot-事件
    spring-事件
    spring-@Component/@ComponentScan注解
    springboot-Date日期时间问题
    enginx:基于openresty,一个前后端统一,生态共享的webstack实现
  • 原文地址:https://www.cnblogs.com/fuyaozhishang/p/8310281.html
Copyright © 2011-2022 走看看