私のアプリに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);
によるものです。助けてください !!事前に
おかげ
** PrescriptionUpload **の活動で期待されることは明らかではありません。いずれにせよ、あなたのUIを反応させるためには、メイン(UI)スレッドから時間のかかるタスク(** onPictureTaken()**は時間のかかるタスク)を実行する必要があります。 ** AsyncTask **は簡単なツールです。 ** Camera.open()**をメインスレッドからも実行することを強く推奨します。一部のデバイスではかなり高速ですが、他のデバイスでは非常に遅いかもしれません。 –
キャプチャ中にクリックについては、クリック時にCAPTUREボタンを無効にし、処理が終了したらもう一度有効にする必要があります。 –
あなたは私のonClickメソッドのタスクをAsyncTaskに移動する必要があるのですか?私は、AsyncTaskでtakePictureメソッドを呼び出すと言っています。申し訳ありませんが、私がnoobのように聞こえる場合(原因は私です:) – Ayusch