【问题标题】:Android- download file + status bar notification slowing down phoneAndroid-下载文件+状态栏通知拖慢手机
【发布时间】:2011-08-03 15:48:27
【问题描述】:

我目前有一个asynctask,它从服务器下载 mp3。当用户开始下载它时,会创建一个状态栏通知。这会实时显示下载进度。我唯一担心的是手机的速度几乎太慢了。有什么方法可以延迟显示的进度或让我的代码更快吗?谢谢。

代码如下:

public class DownloadFile extends AsyncTask<String, String, String> {
    CharSequence contentText;
    Context context;
    CharSequence contentTitle;
    PendingIntent contentIntent;
    int HELLO_ID = 1;
    long time;
    int icon;
    CharSequence tickerText;
    File file;

    public void downloadNotification() {
        String ns = Context.NOTIFICATION_SERVICE;
        notificationManager = (NotificationManager) getSystemService(ns);

        icon = R.drawable.sdricontest;
        //the text that appears first on the status bar
        tickerText = "Downloading...";
        time = System.currentTimeMillis();

        notification = new Notification(icon, tickerText, time);

        context = getApplicationContext();
        //the bold font
        contentTitle = "Your download is in progress";
        //the text that needs to change
        contentText = "0% complete";
        Intent notificationIntent = new Intent(Intent.ACTION_VIEW);
        notificationIntent.setType("audio/*");
        contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

        notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
        notificationManager.notify(HELLO_ID, notification);
    }

    @Override
    protected void onPreExecute() {
        //execute the status bar notification
        downloadNotification();
        super.onPreExecute();
    }

    @Override
    protected String doInBackground(String... url) {
        int count;
        try {
            URL url2 = new URL(sdrUrl);
            HttpURLConnection connection = (HttpURLConnection) url2.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.connect();

            int lengthOfFile = connection.getContentLength();

            //make the stop drop rave folder
            File sdrFolder = new File(Environment.getExternalStorageDirectory() + "/StopDropRave");
            boolean success = false;

            if (!sdrFolder.exists()) {
                success = sdrFolder.mkdir();
            }
            if (!success) {
                String PATH = Environment.getExternalStorageDirectory()
                        + "/StopDropRave/";
                file = new File(PATH);
                file.mkdirs();
            } else {
                String PATH = Environment.getExternalStorageDirectory()
                        + "/StopDropRave/";
                file = new File(PATH);
                file.mkdirs();
            }

            String[] path = url2.getPath().split("/");
            String mp3 = path[path.length - 1];
            String mp31 = mp3.replace("%20", " ");
            String sdrMp3 = mp31.replace("%28", "(");
            String sdrMp31 = sdrMp3.replace("%29", ")");
            String sdrMp32 = sdrMp31.replace("%27", "'");

            File outputFile = new File(file, sdrMp32);
            FileOutputStream fos = new FileOutputStream(outputFile);

            InputStream input = connection.getInputStream();

            byte[] data = new byte[1024];
            long total = 0;
            while ((count = input.read(data)) != -1) {
                total += count;
                publishProgress("" + (int) (total * 100 / lengthOfFile));
                fos.write(data, 0, count);
            }
            fos.close();
            input.close();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void onProgressUpdate(String... progress) {
        contentText = Integer.parseInt(progress[0]) + "% complete";
        notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
        notificationManager.notify(HELLO_ID, notification);
        super.onProgressUpdate(progress);
    }
}

【问题讨论】:

    标签: android notifications download android-asynctask slowdown


    【解决方案1】:

    我看到了类似的结果,您不需要经常推送更新通知,我将我的更新更改为每秒仅更新几次。 (例如,在 onProgressUpdate 中记录您最后一次调用 notify 的时间,并且仅在您超过上一次调用的 100 毫秒或处于最大值时才调用 notify。

    【讨论】:

    • 是的,您发布的通知过多。仅在百分比实际变化至少 1% 后尝试更新。
    • 听起来不错。你会碰巧有一些示例代码,或者只是知道如何实现它?
    • @dmon - 我如何追踪这个?
    • 好吧,只需在 publishProgress 之前添加一个 int 变量,例如if ((int) (total * 100 / lengthOfFile) &gt; previousProgress) { previousProgress = (int) (total * 100 / lengthOfFile); publishProgress(...); }
    • 所以我在我的 while 循环中添加了这个:int prevprogress = (int) (total * 100 / lengthOfFile); if ((int) (total * 100 / lengthOfFile) &gt; prevprogress) { prevprogress = (int) (total * 100 / lengthOfFile); publishProgress(""+(int) (total * 100 / lengthOfFile)); fos.write(data, 0, count); 它仍然运行得很慢。我做对了吗???
    【解决方案2】:

    我曾经遇到过类似的问题,我使用CountDownTimer 解决了它。

    与@superfell 建议的类似,您可以在下载文件时定期调用 AsyncTask 的进度更新。并且只在特定的时间间隔调用通知管理器。

    在调用CountDownTimer的start()后,每隔固定的时间间隔会调用onTick()函数,无论是定时器超时还是显式调用都会调用onFinish()cancel() 函数只会取消定时器,不会调用onFinish() 方法。

    class DownloadMaterial extends AsyncTask<String, String, String> {
    
        CountDownTimer cdt;
        int id = i;
        NotificationManager mNotifyManager;
        NotificationCompat.Builder mBuilder;
    
        @Override
        protected void onPreExecute() {
            /**
             * Create custom Count Down Timer
             */
            cdt = new CountDownTimer(100 * 60 * 1000, 500) {
                public void onTick(long millisUntilFinished) {
                    mNotifyManager.notify(id, mBuilder.build());
                }
    
                public void onFinish() {
                    mNotifyManager.notify(id, mBuilder.build());
                }
            };
        }
    
        @Override
        protected String doInBackground(String... strings) {
            /**
             * Start timer to update Notification
             * Set Progress to 20 after connection
             * Build Notification
             * Increment Progress
             * Download and Save file
             */
            try {
                mNotifyManager =
                        (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                mBuilder = new NotificationCompat.Builder(context);
                mBuilder.setContentTitle("Downloading File")
                        .setContentText(file_name)
                        .setProgress(0, 100, false)
                        .setOngoing(true)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setPriority(Notification.PRIORITY_LOW);
    
                // Initialize Objects here
                publishProgress("5");
                mNotifyManager.notify(id, mBuilder.build());
                cdt.start();
    
                // Create connection here
                publishProgress("20");
    
                // Download file here
                while ((count = input.read(data)) != -1) {
                    total += count;
                    publishProgress("" + (int) (20 + (total * 80 / fileLength)));
                    output.write(data, 0, count);
                }
            } catch (Exception e) {
                return "Failed";
            }
            return "Success";
        }
    
        @Override
        protected void onProgressUpdate(String... values) {
            /**
             * Update Download Progress
             */
            mBuilder.setContentInfo(values[0] + "%")
                    .setProgress(100, Integer.parseInt(values[0]), false);
        }
    
        @Override
        protected void onPostExecute(String s) {
    
            String title;
            if (s.equals("Success")) {
                title = "Downloaded";
            } else {
                title = "Error Occurred";
            }
            mBuilder.setContentTitle(title)
                    .setContentInfo("")
                    .setOngoing(false)
                    .setProgress(0, 0, false);
            cdt.onFinish();
            cdt.cancel();
        }
    }
    

    最好先调用onFinish(),然后再调用cancel()

    【讨论】:

    • 谢谢,但小图标不见了......所以你可能想添加例如".setSmallIcon(R.mipmap.ic_launcher)"
    • @MartinPfeffer 谢谢。相应地进行了编辑。
    【解决方案3】:

    我也遇到过这个问题。我太频繁地更新进度条WAY(即使进度没有改变),我是这样解决的:

            // While loop from generic download method.
            int previousProgress = 0;
            while ((count = inputStream.read(buff)) != -1) {
                outputStream.write(buff, 0, count);
                totalBytesDownloaded += count;
                int prog = (int) (totalBytesDownloaded * 100 / contentLength);
                if (prog > previousProgress) {
                    // Only post progress event if we've made progress.
                    previousProgress = prog;
                    myPostProgressMethod(prog);
    
                }
            }
    

    现在应用运行良好,用户仍会收到进度通知。

    【讨论】:

    • 不过,如果下载服务器太快,这还不够。
    • @VSG24,嗯?那么更新 UI/进度通知怎么样?老实说,这不是“太快”的服务器故障,可能是您的代码。
    【解决方案4】:

    我遇到了同样的问题,即使间隔为 3 秒,我也无法更新进度条通知,所以经过数小时的挖掘,我意识到每当我们更新通知时,RemoteView 对象都必须重新实例化并重新初始化为 Notification 对象的 contentView。完成此操作后,我能够在很长一段时间内以 100ms-500ms 的间隔更新通知进度条,而不会遇到任何 UI 阻塞。

    注意:如果您不同意,您可以通过在注释掉标记的行后运行此 sn-p 来验证此答案并查看差异。开始严重的 UI 阻塞可能需要大约 5 分钟,这会加热您的设备并可能停止运行。 我尝试使用带有 Android 4.2.2 的 S3 mini 并从服务内的工作线程调用 updateNotification(....) 方法。而且我已经仔细检查过了,不知道当 Notification.Builder 用于相同目的时会发生什么。

    注意:在问了 3 年后才写这个答案的原因是因为我想知道我什至没有找到一个 stackoverflow 答案或其他博客文章用这个非常简单的解决方案来处理这个严重的问题。

    我希望这个答案对像我这样的其他新手有所帮助。 享受吧。

    这是我复制粘贴的代码,您可以直接使用.... 我使用相同的代码更新通知布局,其中包含两个 ProgressBar 和四个 TextView,频率为 500ms-100ms。

    //long mMaxtTimeoutNanos = 1000000000 // 1000ms.
    long mMinTimeNanos     = 100000000;//100ms minimum update limit. For fast downloads.
    long mMaxtTimeoutNanos = 500000000;//500ms maximum update limit. For Slow downloads
    long mLastTimeNanos = 0;
    private void updateNotification(.....){
        // Max Limit
        if (mUpdateNotification || ((System.nanoTime()-mLastTimeNanos) > mMaxtTimeoutNanos)) {
            // Min Limit
            if (((System.nanoTime() - mLastTimeNanos) > mMinTimeNanos)) {
                mLastTimeNanos = System.nanoTime();
                // instantiate new RemoteViews object.
                // (comment out this line and instantiate somewhere
                // to verify that the above told answer is true)
                mRemoteView = new RemoteViews(getPackageName(),
                        R.layout.downloader_notification_layout);
                // Upate mRemoteView with changed data
                ...
                ...
                // Initialize the already existing Notification contentView
                // object with newly instatiated mRemoteView.
                mNotification.contentView = mRemoteView;
                mNotificationManager.notify(mNotificatoinId, mNotification);
                mUpdateNotification = false;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 2014-07-15
      相关资源
      最近更新 更多