java - Android - 在一部手机上压缩位图非常慢,在另一部手机上很快

标签 java android performance bitmap compression

我正在编写一个具有简单相机功能的应用程序。我在我的主要 Activity 中拍照,然后启动一个新线程来旋转图像,添加透明水印并将其另存为 .PNG。

此应用程序在运行自定义 rom:AOKP、Android 4.4.2 的三星 galaxy S3 上运行良好。下面给出的代码的执行总时间约为 2 秒。根据任务管理器,我的应用程序使用了大约 9 Mb 的内存。

当我在我的 galaxy S4 上运行这个应用程序时,运行标准(root)Android 4.4.2,执行时间超过 27 秒。根据任务管理器,该应用程序使用了大约 124 Mb 的内存(太多了)。有时应用会崩溃并抛出 OutOfMemory 错误,这在 S3 上不会发生。

这是负责在我的 SaveThread 中保存图像的代码 fragment :

            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 时,这一行确实显示了扫描的文件路径。

我尝试改变压缩质量,但它并没有对速度或内存使用产生重大影响。我无法弄清楚是什么导致了 RAM 使用和执行时间的巨大差异。是什么导致了这种差异,我该如何解决?

编辑:为了完整起见,这是压缩在 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

最佳答案

我想通了。这是我犯的一个非常愚蠢的错误。我正在压缩为 .PNG 但另存为 .JPEG,这显然是某些设备的问题。 3096x4128 图像的压缩现在需要 2 秒,我认为这是正常的(在 100%)。

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

关于java - Android - 在一部手机上压缩位图非常慢,在另一部手机上很快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28322503/

相关文章:

java - 在 Parse 上使用 Google+ 登录

java - 使用 LSOutput 在 xml 序列化期间指定换行符类型

android - Android Gradle依赖关系

android - 使用样式和主题为自定义属性创建默认值

android - Android 中的嵌入式 Unity 使应用程序崩溃

sql-server - 报表数据库的最佳解决方案

c++ - 如何衡量应用程序每秒可以产生多少结果

java - 找不到页面 404 Apache Tomcat

java - 如何计算24小时过去与否

database - AJAX 导致更多 "chattiness"