我正在建立一个应用程序,需要从应用程序内相机拍照的方法,但对于一些安卓设备(旧设备或低内存),它是相当冻结时,拍照触发。有没有什么代码可以修改或优化,让用户体验更好?
//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();
}
});
}谢谢你的帮助。
发布于 2021-05-20 02:55:11
通常,我建议您单步执行代码并查看在每一行上生成的大量内存资源,如果完成,请考虑在遍历整个方法时积极地将这些资源设置为null。
例如,您有一个名为temp的变量,它的大小为"Y“个字节,您似乎要旋转它,然后再也不使用temp。如果picture是temp的旋转副本,那么您现在已经使用了2Y字节的内存来保存temp和picture。我怀疑,如果你在创建picture后简单地将temp设置为null,你可能会释放一半的内存,而这些内存是你的旧/慢手机非常需要的。
采用相同的概念,并遵循您的方法的其余部分,看看是否可以找到其他优化。基本上,在创建不会使用的图像数据副本的任何地方,都应该立即将其设置为null,以便垃圾收集器可以积极地将其丢弃。
发布于 2021-05-20 21:02:38
首先,你需要一些变量:
byte[] byteArray_IMG;
String currentPhotoPath;
static final int REQUEST_TAKE_PHOTO = 1;
ImageView imageView; // maybe you need show the photo before send it然后定义拍摄照片的方法:
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(getApplicationContext(),Error takin the photo",Toast.LENGTH_LONG).show();
}
// Continue only if the File was successfully created
if (photoFile != null) {
path_img = photoFile.toString();
Uri photoURI = FileProvider.getUriForFile(this,"com.app.yournmamepackage.fileprovider" , photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}创建创建文件镜像的方法
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}覆盖活动结果以:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode,data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
/* Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
imageView.setImageBitmap(imageBitmap);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byteArray_IMG = stream.toByteArray();*/
MediaScannerConnection.scanFile(this, new String[]{path_img}, null,
new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
Log.i("path",""+path);
}
});
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Bitmap imageBitmap = BitmapFactory.decodeFile(path_img);
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 14, stream);
imageView.setImageBitmap(imageBitmap);
byteArray_IMG = stream.toByteArray();
}
}记住这一点非常重要
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 25, stream)
// 25 is photo quality 0-100然后,您可以在异步过程中上传图片
发布于 2021-05-22 16:28:06
首先,在您的活动/片段中的onCreate()方法上初始化这些变量
val FILE_NAME:String="photo.jpg" //give any name with.jpg extension
private var imageuri: Uri?=null
val REQUEST_IMAGE=111现在打开摄像头
val intent: Intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
photofile = getphotofile(FILE_NAME)
imageuri = activity?.let { it1 -> FileProvider.getUriForFile(it1, "//your package name here//.fileprovider", photofile) } //put your package name
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageuri)
startActivityForResult(int, REQUEST_IMAGE)onActivityResult()方法
if(requestCode==REQUEST_IMAGE && resultCode == Activity.RESULT_OK){
val progressdialog: ProgressDialog = ProgressDialog(activity)
progressdialog.setTitle("Sending Image....")
progressdialog.show() //start your progressdialog
val ref= FirebaseDatabase.getInstance().reference
val messagekey=ref.push().key //create a key to store image in firebase
var bmp: Bitmap?=null
try {
bmp=MediaStore.Images.Media.getBitmap(activity?.contentResolver,imageuri) //get image in bitmap
} catch (e: IOException) {
e.printStackTrace();
}
val baos= ByteArrayOutputStream()
bmp!!.compress(Bitmap.CompressFormat.JPEG,50,baos) //compress the quality of image to 50 from 100
val fileinBytes: ByteArray =baos.toByteArray()
val store: StorageReference = FirebaseStorage.getInstance().reference.child("Chat Images/") //create a child reference in firebase
val path=store.child("$messagekey.jpg") //store a message in above reference with the unique key created above with .jpg extension
val uploadTask: StorageTask<*>
uploadTask=path.putBytes(fileinBytes) //it will upload the image to firebase at given path
uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
if (!task.isSuccessful) {
task.exception?.let {
throw it
}
Toast.makeText(activity, "Upload Failed", Toast.LENGTH_SHORT).show()
}
return@Continuation path.downloadUrl
}).addOnCompleteListener { task->
if(task.isSuccessful){
url=task.result.toString() //get the url of uploaded image
//Do what you want with the url of your image
progressdialog.dismiss()
Toast.makeText(activity, "Image Uploaded", Toast.LENGTH_SHORT).show()
}
}.addOnFailureListener { e->
progressdialog.dismiss()
Toast.makeText(activity, "Failed " + e.message, Toast.LENGTH_SHORT)
.show();
}
uploadTask.addOnProgressListener { task->
var progress:Double=(100.0*task.bytesTransferred)/task.totalByteCount
progressdialog.setMessage("Sending ${progress.toInt()}%") //this will show the progress in progress bar 0-100%
}
}https://stackoverflow.com/questions/67428809
复制相似问题