Android:当我终止我的应用程序时无法更新自定义通知

Android: Unable to update custom notification when I kill my app

我在服务中一个接一个地下载多个文件。我想在通知中更新下载进度。但是当我终止我的应用程序时,我的通知不会更新。下载在不同的线程上工作。当应用程序为 运行 时,下载工作正常。当我从最近的部分杀死应用程序时,我无法更新通知。

这是我的 DownloadService class

public class DownloadService extends Service {

public static DownloadMap<String, Downloadables> map = new DownloadMap<String, Downloadables>();
private static Thread thread;
private DownloadCancelReceiver receiver;

public DownloadService() {
}

public class BackgroundThread extends Thread {
    int serviceId;
    private DownloadMap<String, Downloadables> map;


    private SpeedRevisionDatabase helper;

    private final int notificationId = 1;
    private RemoteViews remoteViewsSmall, remoteViewsBig;
    private NotificationManagerCompat notificationManager;
    private NotificationCompat.Builder mBuilder, mBuilderComplete, downloadFailBuilder;

    public BackgroundThread(int serviceId, DownloadMap<String, Downloadables> map) {
        this.serviceId = serviceId;
        this.map = new DownloadMap<>();
        this.map.putAll(map);
    }

    @Override
    public void run() {

        remoteViewsSmall = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_notification_small);
        remoteViewsBig = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_notification);

        Intent cancelDownload = new Intent("CANCEL_DOWNLOAD");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, cancelDownload, 0);
        remoteViewsBig.setOnClickPendingIntent(R.id.tvCancel, pendingIntent);

        notificationManager = NotificationManagerCompat.from(DownloadService.this);
        mBuilder = new NotificationCompat.Builder(DownloadService.this, "default");
        initChannels(DownloadService.this);
        mBuilder.setContentTitle("Download is in progress")
                .setContentText("Please wait...")
                .setSmallIcon(R.mipmap.download)
                .setOngoing(true)
                .setCustomContentView(remoteViewsSmall)
                .setCustomBigContentView(remoteViewsBig)
                .setPriority(NotificationCompat.PRIORITY_HIGH);

        notificationManager.notify(notificationId, mBuilder.build());

        if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

        try {

            String path = getApplicationContext().getApplicationInfo().dataDir + "/" + "UEP";
            File uepFolder = new File(path);

            if (!uepFolder.exists()) {
                uepFolder.mkdir();
            }

            int i = 0;
            while (map.entrySet().iterator().hasNext()) {
                Log.e("WhileCheck", "Now i is " + i);
                Map.Entry data = (Map.Entry) map.entrySet().iterator().next();
                try {
                    Downloadables download = (Downloadables) data.getValue();
                    if (NetworkUtil.getConnectivityStatus(getApplicationContext()) == 0) {
                        throw new InternetDisconnectedException("Internet Disconnected");
                    }

                    HttpURLConnection urlConnection;
                    InputStream inputStream;

                    //finding file on internet
                    try {
                        URL url = new URL(download.URL);
                        if (url.toString().endsWith(".xps")) {
                            url = new URL(url.toString().replace(".xps", ".pdf"));
                        }

                        urlConnection = (HttpURLConnection) url.openConnection();
                        urlConnection.connect();
                        inputStream = urlConnection.getInputStream();

                    } catch (IOException e) {
                        Log.e("IOException", "" + e.getMessage());
                        i++;
                        map.remove(data.getKey());
                        notificationManager.notify(notificationId, mBuilder.build());
                        continue;
                    }

                    //Downloading file over internet
                    File file = new File(uepFolder + "/" + download.FileName + "" + download.Format + ".download");
                    try {
                        int fileSize = urlConnection.getContentLength();
                        FileOutputStream fileOutput = new FileOutputStream(file);
                        byte[] buffer = new byte[1024];
                        int bufferLength = 0;
                        int count = 0;
                        int previousProgress = 0;
                        while ((bufferLength = inputStream.read(buffer)) > 0) {

                            if (this.isInterrupted()) {
                                throw new InterruptedException("Thread has been kill (Destroyed)");
                            }

                            fileOutput.write(buffer, 0, bufferLength);
                            count += bufferLength;

                            int progress = (int) (count * 100L / (float) fileSize);

                            if (previousProgress > 999) {
                                updateProgress(map.insertedCount, i, progress, download.Name);
                                notificationManager.notify(notificationId, mBuilder.build());
                                previousProgress = 0;
                            }
                            previousProgress++;
                        }
                        fileOutput.close();
                    } catch (IOException e) {
                        Log.e("IOException", "" + e.getMessage());
                        i++;
                        map.remove(data.getKey());
                        continue;
                    }

                    File actualFile = new File(uepFolder + "/" + download.FileName + "" + download.Format);
                    file.renameTo(actualFile);
                    Log.e("Downloaded",""+actualFile.getAbsoluteFile());

                } catch (InterruptedException | InternetDisconnectedException e) {
                    throw e;
                }
                i++;
                map.remove(data.getKey());
                Log.e("Downloaded", "Remaining files are "+map.size());
            }
            Log.e("WhileCheck", "While End");


            // Due to thread, sometime the sequence of code flow is not in correct flow, and "Download complete" Notifaction is getting shown
            // Hence this check is required.
            if (this.isInterrupted()) {
                throw new InterruptedException("Thread has been kill (Destroyed)");
            }

            notificationManager.cancel(notificationId);

            mBuilderComplete = new NotificationCompat.Builder(DownloadService.this, "default");
            initChannels(DownloadService.this);
            mBuilderComplete.setOngoing(false)
                    .setContentTitle("Download Complete")
                    .setColor(Color.WHITE)
                    .setSmallIcon(R.drawable.download);
            notificationManager.notify(2, mBuilderComplete.build());

            Log.e("DownloadingService", "File downloaded successfully");
            stopSelf();
            map.insertedCount = 0;

        } catch (InterruptedException e) {
            closeNotification();
            Log.e("InterruptedException", "" + e.getMessage());
        } catch (InternetDisconnectedException e) {
            stopSelf();
            closeNotification();
            showNotification("Internet disconnected", "Download failed. Try again later.");
            Log.e("InternetDisconnect", "" + e.getMessage());
        }
    }

    private void updateProgress(int totalFiles, int currentFileCount, int currentProgress, String fileName) {

        remoteViewsSmall.setTextViewText(R.id.tvOverAll, currentFileCount + "/" + totalFiles);
        remoteViewsSmall.setProgressBar(R.id.overallProgress, totalFiles, currentFileCount, false);

        remoteViewsBig.setTextViewText(R.id.tvOverAll, currentFileCount + "/" + totalFiles);
        remoteViewsBig.setTextViewText(R.id.tvFileName, "Downloading " + fileName);
        remoteViewsBig.setTextViewText(R.id.tvCurrentProgress, currentProgress + "%");
        remoteViewsBig.setProgressBar(R.id.overallProgress, totalFiles, currentFileCount, false);
        remoteViewsBig.setProgressBar(R.id.currentProgress, 100, currentProgress, false);
    }

    public void closeNotification() {
        if (notificationManager != null)
            notificationManager.cancel(notificationId);
    }

    public void showNotification(String title, String message) {
        downloadFailBuilder = new NotificationCompat.Builder(DownloadService.this, "default");
        initChannels(DownloadService.this);
        downloadFailBuilder.setOngoing(false)
                .setContentTitle(title)
                .setContentText(message)
                .setColor(Color.WHITE)
                .setSmallIcon(android.R.drawable.stat_sys_warning);
        notificationManager.notify(3, downloadFailBuilder.build());
    }
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent != null) {
        ArrayList<Downloadables> list = (ArrayList<Downloadables>) intent.getSerializableExtra("downloadList");
        for (Downloadables d : list) {
            String key = d.Name + "" + d.FileName;
            map.put(key, d);
        }

        if (thread == null || !thread.isAlive()) {

            thread = new BackgroundThread(startId, map);
            receiver = new DownloadCancelReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
            intentFilter.addAction("CANCEL_DOWNLOAD");
            registerReceiver(receiver, intentFilter);
            thread.start();
        }
    }
    return START_STICKY;
}

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

@Override
public void onDestroy() {
    Log.e("Service", " Stop");
    try {
        thread.interrupt();
    } catch (Exception e) {
        Log.e("Exception", "" + e.getMessage());
    }

    map.clear();
    unregisterReceiver(receiver);
    //closeNotification();

}

public static class DownloadCancelReceiver extends BroadcastReceiver {

    public DownloadCancelReceiver() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equalsIgnoreCase("CANCEL_DOWNLOAD")) {
            Intent intent1 = new Intent(context, DownloadService.class);
            context.stopService(intent1);
        }
    }
}

public void initChannels(Context context) {
    if (Build.VERSION.SDK_INT < 26) {
        return;
    }

    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    NotificationChannel channel = new NotificationChannel("default", "Channel name", NotificationManager.IMPORTANCE_LOW);
    channel.setDescription("Channel description");
    channel.setImportance(NotificationManager.IMPORTANCE_LOW);
    channel.setSound(null, null);
    notificationManager.createNotificationChannel(channel);
}

private class InternetDisconnectedException extends Exception {

    public InternetDisconnectedException(String message) {
        super(message);
    }
}

public static class DownloadMap<String, Downloadables> extends HashMap<String, Downloadables> {

    public int insertedCount;

    @Override
    public Downloadables put(String key, Downloadables value) {
        insertedCount++;
        return super.put(key, value);
    }
}
}

然后从 activity 我开始这样的服务。

ArrayList<Downloadables> list = helper.GetVideoFileList();
Intent intent1 = new Intent(SRDownloadActivity.this, DownloadService.class);
intent1.putExtra("downloadList", list);
startService(intent1);

我什至可以在下载过程中将文件添加到 HashMap。它也很好用。

我无法弄清楚为什么它不在后台 运行 因为它在不同的线程上。

这是我的通知

线程被 Android OS 杀死,即使主应用程序仍在运行并且它们无法访问 UI 这就是为什么你应该使用 AsyncTask class 它就像一个在后台工作的线程,但它可以访问主线程的 UI。而 jobdispatcher class 可以帮助你在后台分配工作

这里有一个很好的教程https://youtu.be/das7FmQIGik