首页 > 解决方案 > 从Android应用内摄像头拍照并将其上传到服务器的更有效方法

问题描述

我正在构建一个需要从应用内相机拍照的方法的应用程序,但是对于某些 Android 设备(旧设备或低内存),触发拍照时它非常冻结。我可以修改或优化任何代码以使用户体验更好吗?

//this function trigger to take picture (or screenshot) from user screen
    private void captureImage() {
        mPreview.setDrawingCacheEnabled(true);
        final Bitmap[] drawingCache = {Bitmap.createBitmap(mPreview.getDrawingCache())};
        mPreview.setDrawingCacheEnabled(false);

     mCameraSource.takePicture(null, bytes -> {
            int orientation = Exif.getOrientation(bytes);
            Bitmap temp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            Bitmap picture = rotateImage(temp, orientation);
            assert picture != null;
            Bitmap overlay = Bitmap.createBitmap(mGraphicOverlay.getWidth(), mGraphicOverlay.getHeight(), picture.getConfig());
            Canvas canvas = new Canvas(overlay);

            Matrix matrix = new Matrix();
            matrix.setScale((float) overlay.getWidth() / (float) picture.getWidth(), (float) overlay.getHeight() / (float) picture.getHeight());

            // mirror by inverting scale and translating
            matrix.preScale(-1, 1);
            matrix.postTranslate(canvas.getWidth(), 0);

            Paint paint = new Paint();
            canvas.drawBitmap(picture, matrix, paint);
            canvas.drawBitmap(drawingCache[0], 0, 0, paint);

//this function to save picture taken and put it on app storage cache
            try {
                String mainpath = getApplicationContext().getFilesDir().getPath() + separator + "e-Presensi" + separator;
                File basePath = new File(mainpath);
                if (!basePath.exists())
                    Log.d("CAPTURE_BASE_PATH", basePath.mkdirs() ? "Success" : "Failed");

//this function to get directory path of saved photo
                String path = mainpath + "photo_" + getPhotoTime() + ".jpg";
                String namafotoo = "photo_" + getPhotoTime() + ".jpg";
                filePath = path;

                namafoto = namafotoo;
                SessionManager.createNamaFoto(namafoto);

                File captureFile = new File(path);
                boolean sucess = captureFile.createNewFile();
                if (!captureFile.exists())
                    Log.d("CAPTURE_FILE_PATH", sucess ? "Success" : "Failed");
                FileOutputStream stream = new FileOutputStream(captureFile);
                overlay.compress(Bitmap.CompressFormat.WEBP, 60, stream);
                stream.flush();
                stream.close();
                if (!picture.isRecycled()) {
                    picture.recycle();
                }

                if (drawingCache[0] != null && !drawingCache[0].isRecycled()) {
                    drawingCache[0].recycle();
                    drawingCache[0] = null;
                }
                mPreview.setDrawingCacheEnabled(false);
                uploadPicture();
                finish();

            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

谢谢你的帮助。

标签: javaandroid

解决方案


一般来说,我建议您单步执行您的代码并查看您在每一行上生成的大量内存资源,并在完成整个方法时考虑将它们设置为空。

例如,您有一个名为temp“Y”字节的变量,您似乎会旋转它,然后再不使用temp它。如果picture是的旋转副本,temp那么您现在已经使用了 2Y 字节的内存来保存temppicture. 我怀疑如果您temp在创建后简单地设置为 null picture,您可能会释放您的旧/较慢手机急需的一半内存。

采用相同的概念并继续使用其余方法,看看是否可以找到其他优化。基本上,在您创建不打算使用的图像数据副本的任何地方,您都应该立即将其设置为 null,以便垃圾收集器可以积极地将其丢弃。


推荐阅读