在Android中运行多个并行下载

时间:2015-09-14 07:21:18

标签: android android-service

首先,我扩展了IntentService以构建我的DonwloadService课程。没关系,但是已经创建了下载队列,第二次下载必须等待第一次完成等等。

所以我决定扩展Service类(在docs之后)。我刚刚添加了下载功能和发布结果的功能(由活动中的接收者监听):

    public class DownloadService extends Service
{
    private static final String TAG = DownloadService.class.getSimpleName();

    public static final String EXTRA_DOWNLOAD = "EXTRA_DOWNLOAD";
    public static final String EXTRA_POSITION = "EXTRA_POSITION";
    public static final String INTENT_NOTIFICATION = "INTENT_NOTIFICATION";
    public static final String EXTRA_RESULT = "EXTRA_RESULT";
    public static final String EXTRA_PROGRESS = "EXTRA_PROGRESS";
    public static final String EXTRA_PATH = "EXTRA_PATH";
    public static final String EXTRA_INDETERMINABLE = "EXTRA_INDETERMINABLE";
    public static final int RESULT_PROGRESS = 123;

    private int mResult = Activity.RESULT_CANCELED;

    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;

    private final class ServiceHandler extends Handler
    {
        public ServiceHandler(Looper looper)
        {
            super(looper);
        }

        @Override
        public void handleMessage(Message message)
        {
            // Download file
            download(message.getData());

            // Stop the service using the startId, so that we don't stop
            // the service in the middle of handling another job
            stopSelf(message.arg1);
        }
    }

    @Override
    public void onCreate()
    {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread handlerThread = new HandlerThread("DownloadServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        handlerThread.start();

        // Get the HandlerThread's Looper and use it for our Handler
        mServiceLooper = handlerThread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        // For each start request, send a message to start a job and deliver the
        // start ID so we know which request we're stopping when we finish the job
        Message message = mServiceHandler.obtainMessage();
        message.setData(intent.getExtras());
        message.arg1 = startId;
        mServiceHandler.sendMessage(message);

        return START_REDELIVER_INTENT;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent)
    {
        // No binding provided
        return null;
    }

    @Override
    public void onDestroy()
    {
        Log.d(TAG, "Service done");
    }

    /**
     * Handles file download
     *
     * @param bundle
     */
    private void download(Bundle bundle)
    {
        if (bundle != null) {
            return;
        }

        Download download = bundle.getParcelable(EXTRA_DOWNLOAD);
        int position = bundle.getInt(EXTRA_POSITION, -1);

        File downloadedFile = new File(Environment.getExternalStorageDirectory(), position + ".jpg");
        if (downloadedFile.exists()) {
            downloadedFile.delete();
        }

        FileOutputStream fileOutputStream = null;

        int filesize = -1;

        try {

            fileOutputStream = new FileOutputStream(downloadedFile.getPath());

            URL url = new URL(download.getUrl());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            filesize = connection.getContentLength();

            InputStream reader = new BufferedInputStream(connection.getInputStream());

            byte data[] = new byte[1024];

            int next = -1;
            int total = 0;
            while ((next = reader.read(data)) != -1) {
                mResult = RESULT_PROGRESS;
                total += next;
                publishResult(downloadedFile.getAbsolutePath(),
                        (filesize > 0) ? Math.round(total * 100 / filesize) : Math.round(total / 1024),
                        position, filesize <= 0);

                fileOutputStream.write(data, 0, next);
            }

            mResult = Activity.RESULT_OK;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        publishResult(downloadedFile.getAbsolutePath(), 100, position, filesize <= 0);

    }

    private void publishResult(String downloadPath, int progress, int positionInList,
                               boolean indeterminable)
    {
        Intent intent = new Intent(INTENT_NOTIFICATION);
        intent.putExtra(EXTRA_PATH, downloadPath);
        intent.putExtra(EXTRA_PROGRESS, progress);
        intent.putExtra(EXTRA_POSITION, positionInList);
        intent.putExtra(EXTRA_INDETERMINABLE, indeterminable);
        intent.putExtra(EXTRA_RESULT, mResult);
        sendBroadcast(intent);
    }
}

但仍有下载队列,没有并行下载。

1 个答案:

答案 0 :(得分:1)

如果要在不同的数据集上重复运行任务,但一次只需要执行一次执行,IntentService就可以满足您的需求。要在资源可用时自动运行任务,或允许多个任务同时运行(或两者都运行),您需要提供托管的线程集合。为此,请使用ThreadPoolExecutor的实例,该实例在其池中的线程空闲时从队列运行任务。要运行任务,您只需将其添加到队列中即可。

<强>参考: Creating a Manager for Multiple Threads