使用改造库处理带有通知的多个下载

时间:2016-07-24 07:15:22

标签: android service download

我正在关注a tutorial to download files using the Retrofit library

我的应用程序的UI有几个不同的按钮,使用上述方法下载不同的文件。问题是当有人在按下第一个按钮后按下另一个按钮时,它会排队并在第一次完成后启动。我想让它立刻开始。

以下是DownloadService的代码:

public class DownloadService extends IntentService {

    public DownloadService() {
        super("Download Service");
    }

    private int totalFileSize;
    private NotificationCompat.Builder notificationBuilder;
    private NotificationManager notificationManager;

    @Override
    protected void onHandleIntent(Intent intent) {
        MyApp x = (MyApp)getApplicationContext();
        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_file_download_deep_orange_a400_18dp)
                .setContentTitle("Downloading")
                .setContentText("Please wait...")
                .setAutoCancel(true);
        notificationManager.notify(x.ID, notificationBuilder.build());
        Log.i("Paras", "onHandleIntent: " + x.filename + x.url);
        initDownload(x.filename,x.url,x.ID);

    }

    private void initDownload(String filename, String url, int id) {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://dl.dropboxusercontent.com/")
                .build();

        RequestInterface.RetrofitInterface retrofitInterface = retrofit.create(RequestInterface.RetrofitInterface.class);

        Call<ResponseBody> request = retrofitInterface.downloadFile(url);
        try {

            downloadFile(request.execute().body(),filename,id);

        } catch (IOException e) {

            e.printStackTrace();
            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();

        }
    }

    private void downloadFile(ResponseBody body, String filename,int id) throws IOException {

        int count;
        byte data[] = new byte[1024 * 4];
        long fileSize = body.contentLength();
        InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
        File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
        OutputStream output = new FileOutputStream(outputFile);
        long total = 0;
        long startTime = System.currentTimeMillis();
        int timeCount = 1;

        while ((count = bis.read(data)) != -1) {
            total += count;
            totalFileSize = (int) (fileSize / (Math.pow(1, 2))) / 1000;
            double current = Math.round(total / (Math.pow(1, 2))) / 1000;

            int progress = (int) ((total * 100) / fileSize);

            long currentTime = System.currentTimeMillis() - startTime;

            Download download = new Download();
            download.setTotalFileSize(totalFileSize);

            if (currentTime > 1000 * timeCount) {
                download.setCurrentFileSize((int) current);
                download.setProgress(progress);
                sendNotification(download,id);
                timeCount++;
            }

            output.write(data, 0, count);
        }

        onDownloadComplete(filename,id);
        output.flush();
        output.close();
        bis.close();

    }

    private void sendNotification(Download download, int id) {

        sendIntent(download);
        notificationBuilder.setProgress(100, download.getProgress(), false);
        notificationBuilder.setContentText("Downloading file " + download.getCurrentFileSize() + "/" + totalFileSize + " KB");
        notificationManager.notify(id, notificationBuilder.build());
    }

    private void sendIntent(Download download) {

        Intent intent = new Intent(subject.MESSAGE_PROGRESS);
        intent.putExtra("download", download);
        LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
    }

    private void onDownloadComplete(String filename,int id) {
        try {

            Download download = new Download();
            download.setProgress(100);
            sendIntent(download);

            notificationManager.cancel(id);
            notificationBuilder.setProgress(0, 0, false);
            notificationBuilder.setContentText("Tap to open");
            notificationManager.notify(id, notificationBuilder.build());

            String path1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename;

            File file = new File(path1);
            Uri uri_path = Uri.fromFile(file);
            String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension
                    (MimeTypeMap.getFileExtensionFromUrl(path1));

            Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
            intent.setType(mimeType);
            intent.setDataAndType(uri_path, mimeType);
            PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
            String string = filename;
            notificationBuilder
                    .setContentIntent(pIntent)
                    .setAutoCancel(true)
                    .setContentTitle(string + " Downloaded");
            Log.i("Paras", "onDownloadComplete: " + string);
            notificationManager.notify(id, notificationBuilder.build());
        } catch (Exception ex) {

        }
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {

    }
}

然后我阅读了IntentServiceService类。 Service类允许同时下载吗?我试过这样的事情:

public class DownloadService extends Service {

    public DownloadService() {
        super();
    }

    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;

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

        @Override
        public void handleMessage(Message msg) {
            MyApp x = (MyApp)getApplicationContext();
            notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            notificationBuilder = new NotificationCompat.Builder(getBaseContext())
                    .setSmallIcon(R.drawable.ic_file_download_deep_orange_a400_18dp)
                    .setContentTitle("Downloading")
                    .setContentText("Please wait...")
                    .setAutoCancel(true);
            notificationManager.notify(x.ID, notificationBuilder.build());
            Log.i("Paras", "onHandleIntent: " + x.filename + x.url);
            initDownload(x.filename,x.url,x.ID);
        }
    }

    @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 thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();

        // Get the HandlerThread's Looper and use it for our Handler
        mServiceLooper = thread.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
        MyApp x = (MyApp)getApplicationContext();
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj= intent.putExtra("ID",x.ID);
        mServiceHandler.sendMessage(msg);

        // If we get killed, after returning from here, restart
        return START_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private int totalFileSize;
    private NotificationCompat.Builder notificationBuilder;
    private NotificationManager notificationManager;

    private void initDownload(String filename, String url, int id) {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://dl.dropboxusercontent.com/")
                .build();

        RequestInterface.RetrofitInterface retrofitInterface = retrofit.create(RequestInterface.RetrofitInterface.class);

        Call<ResponseBody> request = retrofitInterface.downloadFile(url);
        try {

            downloadFile(request.execute().body(),filename,id);

        } catch (IOException e) {

            e.printStackTrace();
            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();

        }
    }

    private void downloadFile(ResponseBody body, String filename,int id) throws IOException {

        int count;
        byte data[] = new byte[1024 * 4];
        long fileSize = body.contentLength();
        InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
        File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
        OutputStream output = new FileOutputStream(outputFile);
        long total = 0;
        long startTime = System.currentTimeMillis();
        int timeCount = 1;

        while ((count = bis.read(data)) != -1) {
            total += count;
            totalFileSize = (int) (fileSize / (Math.pow(1, 2))) / 1000;
            double current = Math.round(total / (Math.pow(1, 2))) / 1000;

            int progress = (int) ((total * 100) / fileSize);

            long currentTime = System.currentTimeMillis() - startTime;

            Download download = new Download();
            download.setTotalFileSize(totalFileSize);

            if (currentTime > 1000 * timeCount) {
                download.setCurrentFileSize((int) current);
                download.setProgress(progress);
                sendNotification(download,id);
                timeCount++;
            }

            output.write(data, 0, count);
        }

        onDownloadComplete(filename,id);
        output.flush();
        output.close();
        bis.close();

    }

    private void sendNotification(Download download, int id) {

        sendIntent(download);
        notificationBuilder.setProgress(100, download.getProgress(), false);
        notificationBuilder.setContentText("Downloading file " + download.getCurrentFileSize() + "/" + totalFileSize + " KB");
        notificationManager.notify(id, notificationBuilder.build());
    }

    private void sendIntent(Download download) {

        Intent intent = new Intent(subject.MESSAGE_PROGRESS);
        intent.putExtra("download", download);
        LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
    }

    private void onDownloadComplete(String filename,int id) {
        try {

            Download download = new Download();
            download.setProgress(100);
            sendIntent(download);

            notificationManager.cancel(id);
            notificationBuilder.setProgress(0, 0, false);
            notificationBuilder.setContentText("Tap to open");
            notificationManager.notify(id, notificationBuilder.build());

            String path1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename;

            File file = new File(path1);
            Uri uri_path = Uri.fromFile(file);
            String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension
                    (MimeTypeMap.getFileExtensionFromUrl(path1));

            Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
            intent.setType(mimeType);
            intent.setDataAndType(uri_path, mimeType);
            PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
            String string = filename;
            notificationBuilder
                    .setContentIntent(pIntent)
                    .setAutoCancel(true)
                    .setContentTitle(string + " Downloaded");
            Log.i("Paras", "onDownloadComplete: " + string);
            notificationManager.notify(id, notificationBuilder.build());
        } catch (Exception ex) {

        }
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {

    }
}

但它没有用。有什么线索我该怎么办?如果需要,我准备提供更多细节。

编辑1: DownloadService在函数“startDownload”上运行,该函数由各种按钮执行。正如您在第二个代码中看到的,类Extends Service。有一个线程可以处理所有这些按钮点击。如果你查看评论,建议我应该使用服务和所有这些点击的不同线程。现在我如何以编程方式创建这么多线程。有近40个按钮可以使用DownloadService。

1 个答案:

答案 0 :(得分:3)

感谢@Lxu,我已经开始工作了。因此,IntentService意味着一次完成一项任务,并且无法同时执行多项任务。我们应该使用Service代替。它允许同时执行多个任务。我们可以在Service内创建多个线程,这些线程将同时执行。将onCreate()的所有代码都放到onStartCommand(),我的问题就解决了。当第一次调用服务时,会调用onCreate(),之后,无论调用多少次服务,都不再调用它。在每次服务调用时,都会执行onStartCommand(),每次都会创建新的线程。就是这样。

这里是完整的代码:

public class DownloadService extends Service {

    public DownloadService() {
        super();
    }
    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;

    int id1;
    int id2;
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            MyApp x = (MyApp)getApplicationContext();
            notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            notificationBuilder = new NotificationCompat.Builder(getApplicationContext())
                    .setSmallIcon(R.drawable.ic_file_download_deep_orange_a400_18dp)
                    .setContentTitle("Downloading")
                    .setContentText("Please wait...")
                    .setAutoCancel(true);
            notificationManager.notify(x.ID, notificationBuilder.build());
            Log.i("Paras", "onHandleIntent: " + x.filename + x.url + "  " + x.ID);
            initDownload(x.filename,x.url,x.ID);
        }
    }
    @Override
    public void onCreate() {
        // Get the HandlerThread's Looper and use it for our Handler
    }

    @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
        HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
        MyApp x = (MyApp)getApplicationContext();
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        mServiceHandler.sendMessage(msg);


        // If we get killed, after returning from here, restart
        return START_STICKY;
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    private int totalFileSize;
    private NotificationCompat.Builder notificationBuilder;
    private NotificationManager notificationManager;

    private void initDownload(String filename, String url, int id) {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://dl.dropboxusercontent.com/")
                .build();

        RequestInterface.RetrofitInterface retrofitInterface = retrofit.create(RequestInterface.RetrofitInterface.class);

        Call<ResponseBody> request = retrofitInterface.downloadFile(url);
        try {

            downloadFile(request.execute().body(),filename,id);

        } catch (IOException e) {

            e.printStackTrace();
            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();

        }
    }

    private void downloadFile(ResponseBody body, String filename,int id) throws IOException {

        int count;
        byte data[] = new byte[1024 * 4];
        long fileSize = body.contentLength();
        InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
        File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
        OutputStream output = new FileOutputStream(outputFile);
        long total = 0;
        long startTime = System.currentTimeMillis();
        int timeCount = 1;
        while ((count = bis.read(data)) != -1) {

            total += count;
            totalFileSize = (int) (fileSize / (Math.pow(1, 2))) / 1000;
            double current = Math.round(total / (Math.pow(1, 2))) / 1000;

            int progress = (int) ((total * 100) / fileSize);

            long currentTime = System.currentTimeMillis() - startTime;

            Download download = new Download();
            download.setTotalFileSize(totalFileSize);

            if (currentTime > 1000 * timeCount) {

                download.setCurrentFileSize((int) current);
                download.setProgress(progress);
                sendNotification(download,id);
                timeCount++;
            }

            output.write(data, 0, count);
        }
        onDownloadComplete(filename,id);
        output.flush();
        output.close();
        bis.close();

    }

    private void sendNotification(Download download, int id) {

        sendIntent(download,id);
        notificationBuilder.setProgress(100, download.getProgress(), false)
                            .setContentTitle("Downloading");
        notificationBuilder.setContentText("Downloading file " + download.getCurrentFileSize() + "/" + totalFileSize + " KB");
        notificationManager.notify(id, notificationBuilder.build());
    }

    private void sendIntent(Download download, int id) {

        Intent intent = new Intent(subject.MESSAGE_PROGRESS);
        intent.putExtra("download", download);
        LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
    }

    private void onDownloadComplete(String filename,int id) {
        try {

            Download download = new Download();
            download.setProgress(100);
            sendIntent(download,id);

            notificationManager.cancel(id);
            notificationBuilder.setProgress(0, 0, false);
            notificationBuilder.setContentText("Tap to open");
            notificationManager.notify(id, notificationBuilder.build());

            String path1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename;

            File file = new File(path1);
            Uri uri_path = Uri.fromFile(file);
            String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension
                    (MimeTypeMap.getFileExtensionFromUrl(path1));

            Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
            intent.setType(mimeType);
            intent.setDataAndType(uri_path, mimeType);
            PendingIntent pIntent = PendingIntent.getActivity(this,(int) System.currentTimeMillis(), intent, 0);
            String string = filename;
            notificationBuilder
                    .setContentIntent(pIntent)
                    .setAutoCancel(true)
                    .setContentTitle(string + " Downloaded");
            Log.i("Paras", "onDownloadComplete: " + string);
            notificationManager.notify(id, notificationBuilder.build());
        }catch (Exception ex){

        }
    }
    @Override
    public void onTaskRemoved(Intent rootIntent) {

    }
}