Android后台下载问题

图片描述

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

阅读 9k
5 个回答

下载任务显然需要在主线程之外处理。
而从当前执行下载任务的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) 删除了管理多个下载任务的代码。

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

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

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

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

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

推荐问题
宣传栏