ホームページ  >  に質問  >  本文

Android后台下载问题

想实现一个后台下载的功能,类似百度地图离线包下载,当下载任务在进行时可以返回其他界面进行其他的操作,下载列表所在的界面为activity1,其他界面为activity2,当在activity1中点击几个任务进行下载时,返回了activity2进行其他操作,过一段时间后再进入activity1怎么显示当前的下载进度?

ringa_leeringa_lee2764日前416

全員に返信(5)返信します

  • 怪我咯

    怪我咯2017-04-17 14:51:17

    下载任务显然需要在主线程之外处理。
    而从当前执行下载任务的activity按了返回键,然后再次进入后,该activity已经被销毁并且重建了,并且一般情况下,在activity被销毁后,我们应该清理新建的线程,以避免无法预料的后果。所以activity重建后显示当前下载信息的各种UI组件也就无法显示正确的状态了。
    而Service与UI无关,可以在后台长时间运行;Bound service 更是允许 app 组件和 service 沟通:发送请求(比如下载请求)、获取状态(比如下载进度)。

    所以,一种可行的解决办法是:

    1. AsyncTask 负责另起一个线程下载,并且定义一个接口,实现该接口就可以获得下载进度及其它下载信息。

    2. Bound Service 负责在后台启动 AsyncTask,并且管理该下载任务;实现 AsyncTask 定义的接口,把获取的下载信息以广播的形式发送出去;

    3. Activity 在绑定到 service 后,就可以通过 service 启动一个下载任务;然后实现一个 broadcast receiver,接收下载信息并更新UI.

    如果对service不了解,可以点这里链接1;对绑定也不了解,可以点这里链接2。

    AsyncTask负责另起一个线程下载

    public class DownloadTask extends AsyncTask<Void, Integer, Long> {
        // 维护下载大小、下载进度、下载速率等信息。
        private long downloadPercent;
    
        // 构造器,指定下载的url和存储路径。
        public DownloadTask(Context context, String url, String path);
        
        @Override
        protected Long doInBackground(Void... params) {
            // 根据获取的url,执行下载任务。
        }
        
        @Override
        protected void onProgressUpdate(Integer... progress) {
            // 定义一个callback,实现该callback的即可获得进度的更新。
            if (listener != null)
                listener.updateProcess(this);
        }

    Bound Service负责在后台启动AsyncTask,并管理下载任务

    public class DownloadService extends Service {    
        // Activity绑定该service后,就可以调用这个方法启动一个下载任务。
        public void startDownloadTask(String url) {
            DownloadTask task = newDownloadTask(url);
            task.execute();    
        }
        
        private DownloadTask newDownloadTask(String url) throws MalformedURLException {
            // 实现该接口就可以获得下载进度及其它下载信息,然后以广播的形式把获取的信息发送出去。
            DownloadTaskListener taskListener = new DownloadTaskListener() {
                @Override
                public void updateProcess(DownloadTask task) {
                    Intent updateIntent = new Intent(ACTION_DOWNLOADING_STATUS);
                    updateIntent.putExtra(MyIntents.PROCESS_PROGRESS, task.getDownloadPercent());
                    sendBroadcast(updateIntent);
                }
            };
            return new DownloadTask(this, url, /path/to/store/, taskListener);
        }
    }

    Activity负责绑定service,实现一个 broadcast receiver,接收下载信息并更新UI

    public class DownloadActivity extends FragmentActivity {
        // 在onStart中绑定service,注册receiver
        protected void onStart();
    
        // 在onStop中取消绑定,取消注册receiver
        protected void onStop();
        
        // 实现一个ServiceConnection,在onServiceConnected()回调方法中获取service
        private ServiceConnection mConnection = new ServiceConnection() {}
        
        // 实现一个BroadcastReceiver,在onReceive()回调方法中获取intent,从中解析下载信息然后更新UI.
        private BroadcastReceiver mDownloadingStatusReceiver = new BroadcastReceiver() {}
        
        // 获取service后,就可以启动一个下载任务了。
        mService.startDownloadTask(URL);
    }

    完整的代码可以从这里获取 https://github.com/li2/DownloadDemo
    这仅仅是一个demo,用于演示bound service和async task是如何实现后台下载任务的。
    该Demo从这个项目里yingyixu/android-download-manager (1) 借用了核心代码;(2) 使用 Binder class实现service,代替原工程中使用的AIDL方式(因为该方式实现复杂,而Binder已经可以满足你的需求,而且容易理解);(3) 删除了管理多个下载任务的代码。

    建议了解实现方法后,直接使用第三方框架。

    返事
    0
  • 迷茫

    迷茫2017-04-17 14:51:17

    据我所知下载进度断点续传什么的是要存在数据库里的,所以把下载进度存在数据库里,下次进入的时候显示这个下载进度,就好了

    返事
    0
  • 迷茫

    迷茫2017-04-17 14:51:17

    既然是后台下载,当这个界面再次显示的时候,获取正在后台下载的任务,显示到当前界面不就行了吗

    返事
    0
  • PHP中文网

    PHP中文网2017-04-17 14:51:17

    可以写一个Service进行后台下载工作,Activity1和该Service绑定,通过Intent及Binder来实现Service和Activity1进行数据交换(即你说的从Activity2回到Activity1时下载进度变化处理),具体实现你需要对Service,Service跟Activity交互有更深的理解了,可以照这个思路去找资料学习和实现,祝你成功。

    返事
    0
  • 天蓬老师

    天蓬老师2017-04-17 14:51:17

    在service中进行下载,Activity1使用bindservice()方法与service绑定,并在service中设置一个回调方法。下载的时候调用这个回调方法把进度传递给Activity1

    返事
    0
  • キャンセル返事