Android - 在某些手机上压缩位图非常缓慢,在另外一些手机上则非常快

4
我正在编写一个简单相机功能的应用程序。我在主活动中拍摄照片,并启动一个新线程旋转图像、添加透明水印并将其保存为 .PNG 格式。
这个应用在我的三星Galaxy S3上运行得非常好,它运行着一个自定义ROM:AOKP,Android 4.4.2。下面给出的代码执行总时间约为2秒。根据任务管理器,我的应用程序使用了约9 MB的内存。
当我在我的Galaxy S4上运行这个应用程序时,运行着原版(已Root)的Android 4.4.2,执行时间超过27秒。根据任务管理器,该应用程序使用了约124 MB的内存(太多了)。偶尔该应用程序会崩溃并抛出OutOfMemory错误,在S3上不会发生。
以下是在SaveThread中保存图像的代码片段:
            TimingLogger tl = new TimingLogger("MyTag", "Saving");            
            String name = new SimpleDateFormat("dd-MM-yyyy_HH-mm-ss")
                    .format(new Date());
            File myNewFolder = new File(path);
            myNewFolder.mkdir();
            File file = new File(path, name + ".JPEG");
            OutputStream imageFileOS;

            // Get EXIF rotation from byte array
            int rotation = getOrientation(data);
            tl.addSplit("Rotation calculated");
            // Convert byte array to bitmap, and watermark bitmap
            Bitmap pictureObject = BitmapFactory.decodeByteArray(data, 0,
                    data.length);
            tl.addSplit("Decoded ByteArray to Bitmap");

            // Rotate bitmap image according to EXIF data
            pictureObject = rotateBitmap(rotation, pictureObject);
            tl.addSplit("Bitmap rotated");
            // Add watermark to rotated bitmap
            Bitmap waterMarkedBitmap = addWaterMarkText(pictureObject);
            tl.addSplit("Bitmap watermarked");
            try {
                imageFileOS = new FileOutputStream(file);
                waterMarkedBitmap.compress(Bitmap.CompressFormat.PNG, 100,
                        imageFileOS);
                tl.addSplit("Bitmap compressed");
                imageFileOS.flush();
                imageFileOS.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

正如您所看到的,我添加了一个定时记录器以找出哪些步骤需要更长时间。以下LogCat返回结果显示将Bitmap压缩为.PNG格式花费了很长时间。我认为这可能与垃圾收集器有关。在执行期间,我的Logcat返回如下:

        02-04 13:57:08.166: I/Choreographer(30003): Skipped 73 frames!  The
        application may be doing too much work on its main thread.
        02-04 13:57:10.528: D/dalvikvm(30003): GC_FOR_ALLOC freed 552K, 19% free 24803K/30324K, paused 48ms, total 49ms
        02-04 13:57:10.628: I/dalvikvm-heap(30003): Grow heap (frag case) to 76.336MB for 51121168-byte allocation
        02-04 13:57:10.918: D/dalvikvm(30003): GC_FOR_ALLOC freed 4K, 7% free 74723K/80248K, paused 23ms, total 23ms
        02-04 13:57:11.019: I/dalvikvm-heap(30003): Grow heap (frag case) to 125.086MB for 51121168-byte allocation
        02-04 13:57:11.859: D/dalvikvm(30003): GC_FOR_ALLOC freed 49923K, 43% free 74723K/130172K, paused 25ms, total 26ms
        02-04 13:57:11.869: I/dalvikvm-heap(30003): Grow heap (frag case) to 125.086MB for 51121168-byte allocation
        02-04 13:57:39.967: D/MyTag(30003): Saving: begin
        02-04 13:57:39.967: D/MyTag(30003): Saving:      3 ms, Rotation calculated
        02-04 13:57:39.967: D/MyTag(30003): Saving:      418 ms, Decoded ByteArray to Bitmap
        02-04 13:57:39.967: D/MediaScannerConnection(30003): Scanning file 7klwibgf7fvntblfd7(7KhzCbvfib7(,6()6)(*._*+6./6*(5QHFG
        02-04 13:57:39.967: D/MyTag(30003): Saving:      939 ms, Bitmap rotated
        02-04 13:57:39.967: D/MyTag(30003): Saving:      96 ms, Bitmap watermarked
        02-04 13:57:39.967: D/MyTag(30003): Saving:      28023 ms, Bitmap compressed
        02-04 13:57:39.967: D/MyTag(30003): Saving:      0 ms, Done saving
        02-04 13:57:39.967: D/MyTag(30003): Saving:      8 ms, Media scanned
        02-04 13:57:39.967: D/MyTag(30003): Saving: end, 29487 ms

我不确定这是否相关,但LogCat行:

D/MediaScannerConnection(30003): Scanning file 7klwibgf7fvntblfd7(7KhzCbvfib7(,6()6)(*._*+6./6*(5QHFG

明显没有显示已扫描文件的路径(尽管它确实起作用)。当我将我的S3连接到Eclipse时,这行代码会显示已扫描文件的路径。

我尝试改变压缩质量,但速度和内存使用方面的变化不大。我无法想象是什么原因导致了内存使用和执行时间上的巨大差异。是什么原因导致了这种差异,我该怎么做才能解决它?

注:为了完整起见,这是在Galaxy S3上进行压缩的速度:

02-04 15:40:47.980: D/MyTag(25536): Saving:      6 ms, Rotation calculated
02-04 15:40:47.980: D/MyTag(25536): Saving:      53 ms, Decoded ByteArray to Bitmap
02-04 15:40:47.980: D/MyTag(25536): Saving:      94 ms, Bitmap rotated
02-04 15:40:47.980: D/MyTag(25536): Saving:      19 ms, Bitmap watermarked
02-04 15:40:47.980: D/MyTag(25536): Saving:      210 ms, Bitmap compressed
02-04 15:40:47.980: D/MyTag(25536): Saving:      0 ms, Done saving
02-04 15:40:47.980: D/MyTag(25536): Saving:      3 ms, Media scanned
02-04 15:40:47.980: D/MyTag(25536): Saving: end, 385 ms

当我在S3上使用前置摄像头拍照时,压缩过程需要更长的时间(我真的不知道为什么...)。
02-04 20:24:31.245: D/MyTag(29496): Saving: begin
02-04 20:24:31.245: D/MyTag(29496): Saving:      2 ms, Rotation calculated
02-04 20:24:31.245: D/MyTag(29496): Saving:      95 ms, Decoded ByteArray to Bitmap
02-04 20:24:31.245: D/MyTag(29496): Saving:      160 ms, Bitmap rotated
02-04 20:24:31.245: D/MyTag(29496): Saving:      25 ms, Bitmap watermarked
02-04 20:24:31.245: D/MyTag(29496): Saving:      4548 ms, Bitmap compressed
02-04 20:24:31.245: D/MyTag(29496): Saving:      0 ms, Done saving
02-04 20:24:31.245: D/MyTag(29496): Saving:      3 ms, Media scanned
02-04 20:24:31.245: D/MyTag(29496): Saving: end, 4833 ms

你尝试过在没有附加调试器的情况下运行它,然后再附加调试器以检查logcat时间戳输出吗?你可能会发现性能有很大的差异(即使2秒压缩一张图片也相当高)。当然,这并不能解决内存问题。那是一个完全不同的问题 - 欢迎来到痛苦的世界! - Adam S
请注意,您正在告诉位图以100%的质量进行压缩 :) 即使降至95%,您也会注意到磁盘上的大小显着减小(内存大小保持不变)。 - Adam S
感谢您的评论。我在Android文档中读到,PNG压缩是无损的,因此无论我使用100%还是80%,它始终都是100%的压缩,所以这并不重要。 - AndroidAddict
我刚刚尝试了一下没有附加调试器,但是没有任何区别,总共仍然需要近30秒的时间。 - AndroidAddict
哦,我没意识到 - 我猜我在文档中错过了那个部分!很抱歉调试器的事情没能解决,这是我以前遇到过的经历。 - Adam S
1
我的 Nexus 7 上需要 30 秒才能处理一张 8 百万像素的照片,感觉像是一个 bug。而同一张照片在 iPhone 6 上不到一秒就能压缩成 PNG 格式。 - jjxtra
1个回答

5

我搞清楚了,是我犯了一个非常愚蠢的错误。我正在压缩成 .PNG 格式,但保存为 .JPEG 格式,这对某些设备来说似乎是一个问题。现在对于一张 3096x4128 的图像进行压缩需要 2 秒钟,我认为这是正常的(在 100% 的情况下)。

虽然这不能解决所有问题。在 S4 上,代码仍然使用超过 100 Mb 的内存,有时会抛出 OutOfMemory 错误。该代码在 S3 上运行完美。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接