2017-02-10 12 views
0

私のアプリにCamera APIを使用しようとしています。写真を撮るボタンをクリックすると、約10秒間UIがハングしてからさらに応答します。Android - カメラAPIが画像のキャプチャと保存に時間がかかります

私はSO hereに投稿を見つけましたが、その解決策はあまり特有ではありませんでした。私はそれがマルチスレッドの問題だと思う。私はアンドロイド開発の初心者であり、マルチスレッドに堪能ではありません。

UploadPrescription.java:

package com.example.ayusch.medomo; 


import android.Manifest; 
import android.content.Context; 
import android.content.Intent; 
import android.content.pm.PackageManager; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.ImageFormat; 
import android.graphics.Matrix; 
import android.hardware.Camera; 
import android.media.ExifInterface; 
import android.os.Build; 
import android.os.Bundle; 
import android.os.Environment; 
import android.support.annotation.NonNull; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.ShareCompat; 
import android.support.v4.content.ContextCompat; 
import android.util.Log; 
import android.util.Size; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Button; 
import android.widget.FrameLayout; 
import android.widget.Toast; 

import java.io.ByteArrayOutputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.File; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.List; 


/** 
* A simple {@link Fragment} subclass. 
*/ 
public class UploadPrescription extends Fragment { 
    private static final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 2; 
    private Camera mCamera = null; 
    private CameraPreview mCameraPreview; 
    private final int REQUEST_CAMERA_PERMISSION = 1; 
    private FrameLayout preview; 
    private File pictureFile; 
    private FileOutputStream fos; 
    private byte[] byteArray; 

    public UploadPrescription() { 
     // Required empty public constructor 
    } 


    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 

     // Inflate the layout for this fragment 
     View root = inflater.inflate(R.layout.fragment_upload_prescription, container, false); 
     preview = (FrameLayout) root.findViewById(R.id.camera_preview); 

     setPreview(); 

     Button captureButton = (Button) root.findViewById(R.id.button_capture); 
     captureButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       Log.i("ayusch", "inside on click"); 
       mCamera.takePicture(null, null, mPicture); 
      } 

     }); 
     return root; 
    } 

    private void setPreview() { 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { 
       setup(); 
      } else { 

       if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { 

        Toast.makeText(getContext(), "Permission needed to use camera", Toast.LENGTH_LONG).show(); 
       } 

       requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); 
      } 
     } else { 
      setup(); 
     } 

    } 


    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 

     if (requestCode == REQUEST_CAMERA_PERMISSION) { 
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       setup(); 
      } else { 
       Toast.makeText(getContext(), "Camera Permission not granted", Toast.LENGTH_LONG).show(); 
       return; 
      } 
     } else if (requestCode == REQUEST_EXTERNAL_STORAGE_PERMISSION) { 
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       proceedtowrite(); 
      } else { 
       Toast.makeText(getContext(), "Storage permission not granted", Toast.LENGTH_LONG).show(); 
       return; 
      } 
     } 
    } 

    public void setup() { 

     mCamera = getCameraInstance(); 
     Camera.Parameters parameters = mCamera.getParameters(); 
     parameters.set("jpeg-quality", 70); 
     parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 
     parameters.setPictureFormat(ImageFormat.JPEG); 
     List<Camera.Size> sizes = parameters.getSupportedPictureSizes(); 
     Camera.Size size = sizes.get(Integer.valueOf((sizes.size() - 1)/2)); //choose a medium resolution 
     parameters.setPictureSize(size.width, size.height); 
     mCamera.setParameters(parameters); 
     mCameraPreview = new CameraPreview(getContext(), mCamera); 
     preview.addView(mCameraPreview); 
    } 

    private Camera getCameraInstance() { 

     Camera camera = null; 
     try { 
      camera = Camera.open(0); 

     } catch (Exception e) { 
      e.printStackTrace(); 
      // cannot get camera or does not exist 
     } 
     return camera; 
    } 

    Camera.PictureCallback mPicture = new Camera.PictureCallback() { 
     @Override 
     public void onPictureTaken(byte[] data, Camera camera) { 
      Log.i("ayusch", "inside onPictureTaken"); 

      pictureFile = getOutputMediaFile(); 

      if (pictureFile == null) { 
       Log.i("ayusch", "Null Picture file, returning..."); 
       return; 
      } 
      try { 
       fos = new FileOutputStream(pictureFile); 

       //////////////////////////////////// 
       Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length); 

       ExifInterface exif = new ExifInterface(pictureFile.toString()); 

       Log.d("ayusch", exif.getAttribute(ExifInterface.TAG_ORIENTATION)); 
       if (exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")) { 
        realImage = rotate(realImage, 90); 
       } else if (exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")) { 
        realImage = rotate(realImage, 270); 
       } else if (exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")) { 
        realImage = rotate(realImage, 180); 
       } else if (exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")) { 
        realImage = rotate(realImage, 90); 
       } 
       ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
       realImage.compress(Bitmap.CompressFormat.PNG, 100, stream); 
       byteArray = stream.toByteArray(); 

       //////////////////////////////////// 
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
        if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { 
         proceedtowrite(); 
        } else { 

         if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { 

          Toast.makeText(getContext(), "Permission needed to store and upload Prescription", Toast.LENGTH_LONG).show(); 
         } 

         requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_PERMISSION); 
        } 
       } else { 
        proceedtowrite(); 
       } 
      } catch (FileNotFoundException e) { 

      } catch (IOException e) { 
      } 
     } 
    }; 

    public void proceedtowrite() { 
     try { 
      fos.write(byteArray); 
      fos.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     Intent i = new Intent(getActivity(), PrescriptionUpload.class); 
     i.putExtra("prescription", pictureFile); 
     startActivity(new Intent(i)); 
    } 

    public static Bitmap rotate(Bitmap bitmap, int degree) { 
     int w = bitmap.getWidth(); 
     int h = bitmap.getHeight(); 

     Matrix mtx = new Matrix(); 
     //  mtx.postRotate(degree); 
     mtx.setRotate(degree); 

     return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); 
    } 

    private static File getOutputMediaFile() { 
     Log.i("ayusch", "Getting output media file"); 
     File mediaStorageDir = new File(
       Environment 
         .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), 
       "MyCameraApp"); 
     if (!mediaStorageDir.exists()) { 
      if (!mediaStorageDir.mkdirs()) { 
       Log.d("MyCameraApp", "failed to create directory"); 
       return null; 
      } 
     } 
     // Create a media file name 
     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") 
       .format(new Date()); 
     File mediaFile; 
     mediaFile = new File(mediaStorageDir.getPath() + File.separator 
       + "IMG_" + timeStamp + ".jpg"); 
     Log.i("ayusch", "Filename = " + mediaFile); 
     return mediaFile; 
    } 

    @Override 
    public void onPause() { 

     super.onPause(); 
     if (mCamera != null) { 
      mCamera.setPreviewCallback(null); 
      mCameraPreview.getHolder().removeCallback(mCameraPreview); 
      mCamera.stopPreview(); 
      mCamera.release(); 

     } 
    } 

    @Override 
    public void onResume() { 

     super.onResume(); 
     try { 
      mCameraPreview.getHolder().removeCallback(mCameraPreview); 
      setPreview(); 

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

    } 
} 

CameraPreview.java:

package com.example.ayusch.medomo; 

import android.content.Context; 
import android.hardware.Camera; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 

import java.io.IOException; 

/** 
* Created by Ayusch on 09-Feb-17. 
*/ 
public class CameraPreview extends SurfaceView implements 
     SurfaceHolder.Callback { 
    private SurfaceHolder mSurfaceHolder; 
    private Camera mCamera; 


    // Constructor that obtains context and camera 
    @SuppressWarnings("deprecation") 
    public CameraPreview(Context context, Camera camera) { 
     super(context); 

     this.mCamera = camera; 
     this.mSurfaceHolder = this.getHolder(); 
     this.mSurfaceHolder.addCallback(this); 
     this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    } 


    @Override 
    public void surfaceCreated(SurfaceHolder surfaceHolder) { 

     try { 

      mCamera.setPreviewDisplay(surfaceHolder); 
      mCamera.setDisplayOrientation(90); 
      mCamera.startPreview(); 
     } catch (IOException e) { 
      // left blank for now 
     } 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 
     Log.i("ayusch", "Inside surfaceDestroyed"); 
     mCamera.stopPreview(); 
     mCamera.release(); 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, 
           int width, int height) { 

     // start preview with new settings 
     try { 
      mCamera.setPreviewDisplay(surfaceHolder); 
      mCamera.startPreview(); 
     } catch (Exception e) { 
      // intentionally left blank for a test 
     } 
    } 
} 

MainActivity.java:

package com.example.ayusch.medomo; 

import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.support.annotation.NonNull; 
import android.support.design.widget.TabLayout; 
import android.support.v4.content.ContextCompat; 
import android.support.v4.view.ViewPager; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.support.v7.widget.Toolbar; 
import android.util.Log; 
import android.view.View; 
import android.widget.Toast; 

public class MainActivity extends AppCompatActivity { 
    private static final int REQUEST_CAMERA_PERMISSION = 1; 
    Toolbar toolbar; 
    TabLayout tabLayout; 
    ViewPager viewPager; 
    ViewPagerAdapter viewPagerAdapter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_main); 
     toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 

     tabLayout = (TabLayout) findViewById(R.id.tabLayout); 
     viewPager = (ViewPager) findViewById(R.id.viewPager); 
     viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager()); 
     viewPagerAdapter.addFragments(new UploadPrescription(), "Upload Prescription"); 
     viewPagerAdapter.addFragments(new OrderByName(), "Enter Medicine Name"); 
     viewPagerAdapter.addFragments(new Contact(), "Contact Us"); 
     viewPager.setAdapter(viewPagerAdapter); 
     tabLayout.setupWithViewPager(viewPager); 

    } 

} 

また、ハング時間の間、私はもう一度ボタンを押すと、アプリクラッシュ:

02-10 19:57:31.481 966-966/com.example.ayusch.medomo E/AndroidRuntime: FATAL EXCEPTION: main 
                     Process: com.example.ayusch.medomo, PID: 966 
                     java.lang.RuntimeException: Camera is being used after Camera.release() was called 
                      at android.hardware.Camera.native_takePicture(Native Method) 
                      at android.hardware.Camera.takePicture(Camera.java:1523) 
                      at android.hardware.Camera.takePicture(Camera.java:1468) 
                      at com.example.ayusch.medomo.UploadPrescription$1.onClick(UploadPrescription.java:73) 
                      at android.view.View.performClick(View.java:5714) 
                      at android.widget.TextView.performClick(TextView.java:10926) 
                      at android.view.View$PerformClick.run(View.java:22589) 
                      at android.os.Handler.handleCallback(Handler.java:739) 
                      at android.os.Handler.dispatchMessage(Handler.java:95) 
                      at android.os.Looper.loop(Looper.java:148) 
                      at android.app.ActivityThread.main(ActivityThread.java:7325) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 

それは私が任意の成功なしで2日以来、それのまわりで私の頭を取得しようとしてきたUploadPrescription.java

のonClickの方法でラインmCamera.takePicture(null, null, mPicture);によるものです。助けてください !!事前に

おかげ

enter image description here

+0

** PrescriptionUpload **の活動で期待されることは明らかではありません。いずれにせよ、あなたのUIを反応させるためには、メイン(UI)スレッドから時間のかかるタスク(** onPictureTaken()**は時間のかかるタスク)を実行する必要があります。 ** AsyncTask **は簡単なツールです。 ** Camera.open()**をメインスレッドからも実行することを強く推奨します。一部のデバイスではかなり高速ですが、他のデバイスでは非常に遅いかもしれません。 –

+0

キャプチャ中にクリックについては、クリック時にCAPTUREボタンを無効にし、処理が終了したらもう一度有効にする必要があります。 –

+0

あなたは私のonClickメソッドのタスクをAsyncTaskに移動する必要があるのですか?私は、AsyncTaskでtakePictureメソッドを呼び出すと言っています。申し訳ありませんが、私がnoobのように聞こえる場合(原因は私です:) – Ayusch

答えて

0

は、私はカメラのプレビューで画面を埋め同様の問題、のための迅速かつ汚い回避策を行なったし、その後、同じようにのscreengrabを捕獲し、必要なときに(かなり応答これは実際には基本的に妥当なフレームレートで一連のフレームを撮影することを可能にしました。

これで十分だと思います。そうでない場合は教えてください。

+0

申し訳ありませんが、私はあなたの解決策を理解できませんでした。プロシージャーの何かについてもっと詳しく述べてください。 – Ayusch

+0

明日詳細に返信しますが、私は答えを編集しますが、私の解決策は画面全体をカメラのプレビューで満たし、画像を撮りたいときにただ画面上のものをただちにキャプチャすることです画像の一部として他のもの(オーバーレイまたは何でも)がキャプチャされることに注意してください。理想的ではないが、私のために働く。これはあなたに適していますか? – HomerPlata

+0

OK ok ....私はあなたの解決策を得ましたが、自分のアクティビティにアクションバーを表示する必要があるため、カメラプレビューで画面を覆うことができません。他に何か提案できますか? – Ayusch

0
 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
    realImage.compress(Bitmap.CompressFormat.PNG, 100, stream); 
    byteArray = stream.toByteArray(); 

Bitmap#compressは、ハードウェアアクセラレーションが不足しているなど、PNG形式では非常に効率が悪いです。保存する前にビットマップのサイズを変更するか、JPEGに圧縮するか、またはネイティブioを使用して生のビットマップをダンプしてください。

関連する問題