با سلام، میخوام در ادامه در مورد آموزش کار کردن با دوربین در اندروید مطالبی رو به اشتراک بزارم.
تو این قسمت میخوام با استفاده از دوربین عکسی گرفته بشه و اون عکس رو در حافظه گوشی ذخیره کنیم.
نکته اول: اکتیویتی به نام UserProfileActivity داریم که یه button داخلش کردیم و داخل Onclick اون button میخوایم عکس گرفته شود و ذخیره شود و در ادامه به سرور ارسال شود.
نکته دوم – تا مرحله سوم بیشتر خود کدهای خام آورده شده، بعد از تغییرات Manifest بهتره برای استفاده از مرحله 4 به بعد رو استفاده کنید.
1- اول از همه داخل Manifest اجازه دسترسی به حافظه داخلی رو بدید.
<manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
2- بعد از گرفتن عکس نیاز به فایلی داریم که عکس در آن ذخیره شود، به این منظور از تابع زیر استفاده می کنیم (داخل Activity مورد نظر استفاده شود – تو این مثال UserProfileActivity):
String mCurrentPhotoPath; 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 mCurrentPhotoPath = image.getAbsolutePath(); return image; }
نکته: برای اندروی قبل از 24 از FileProvide استفاده نمیشد ولی برای اندروید های بیشتر از 24 اگر از FileProvider استفاده نشه به ارور زیر بر خواهید خورد:
.../android.os.FileUriExposedException: file:///storage/emulated/0
برای تنظیمات File provider در قدم اول داخل Manifest تگ providerزیر را وارد کنید:
<application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data> </provider> ... </application>
در خط دوم از تگ provider داریم applicationId که این ID درون فایل buil.gradle قابل دسترس هست.
حال باید فایل file_paths.xml داخل res/xml ساخته بشه:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /> </paths>
3- حال برای گرفتن عکس و فراخوانی intent جدید می توانید از کد زیر استفاده کنید (داخل Activity مورد نظر استفاده شود – تو این مثال UserProfileActivity) :
static final int REQUEST_TAKE_PHOTO = 1; 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) { // Error occurred while creating the File } // Continue only if the File was successfully created if (photoFile != null) { Context context = this; Uri photoURI = FileProvider.getUriForFile(this, context.getPackageName()+ ".provider" , photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE); } }
4- نکته: قبل از فراخوانی کد های فوق بهتره که ابتدا توسط تابع زیر بررسی کنیم که دستگاه مورد نظر دوربین داره یا خیر (داخل Activity مورد نظر استفاده شود – تو این مثال UserProfileActivity) :
/** Sadegh Camera take picture * Checking device has camera hardware or not * */ private boolean isDeviceSupportCamera() { if (getApplicationContext().getPackageManager().hasSystemFeature( PackageManager.FEATURE_CAMERA)) { // this device has a camera return true; } else { // no camera on this device return false; } }
و از طریق زیر بررسیش می کنیم (داخل Activity مورد نظر استفاده شود) :
if (!isDeviceSupportCamera()) { Toast.makeText(getApplicationContext(), "Sorry! Your device doesn't support camera", Toast.LENGTH_LONG).show(); // will close the app if the device does't have camera finish(); } // capture picture captureImage();
captureImage در اصل همان کد نوشته شده در مرحله 3 است که تغییراتی توش دادم و در زیر آورده شده است:
private void captureImage() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //// sadegh added for error : FileUriExposedException intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); Context context = this; fileUri = FileProvider.getUriForFile(this, this.getPackageName() + ".provider", getOutputMediaFile(MEDIA_TYPE_IMAGE)); intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // start the image capture Intent startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE); }
همون طور که تو کد بالا اومده برای ساخت فایل از تابع getOutputMediaFile استفاده شده که کدش میشه:
/** * returning image / video */ private static File getOutputMediaFile(int type) { // External sdcard location File mediaStorageDir = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), AppConfig.IMAGE_DIRECTORY_NAME); // Create the storage directory if it does not exist if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d(TAG, "Oops! Failed create " + AppConfig.IMAGE_DIRECTORY_NAME + " directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); } else if (type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4"); } else { return null; } return mediaFile; }
/** * Here we store the file url as it will be null after returning from camera * app */ @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // save file url in bundle as it will be null on screen orientation // changes outState.putParcelable("file_uri", fileUri); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // get the file url fileUri = savedInstanceState.getParcelable("file_uri"); }
5- ذخیره عکس بر روی سرور (بخش اندروید استادیو) (داخل Activity مورد نظر استفاده شود):
یه Activity و فایل Layout جدا برای صفحه Upload داریم، اسم Activity مورد نظر UploadActivity هست.
خب یه تابع داخل Activity مورد نظرمان داریم (UserProfileActivity) که کدش زیر هست و اکتیویتی آپلود رو فراخوانی می کنه:
private void launchUploadActivity(boolean isImage){ Intent i = new Intent(UserProfileActivity.this, UploadActivity.class); i.putExtra("filePath", fileUri.getPath()); i.putExtra("isImage", isImage); startActivity(i); }
از تابع زیر نیز برای فراخوانی UploadActivity استفاده می کنیم (باز هم داخل Activity مورد نظر که اینجاUserProfileActivity استفاده میشه):
/** * Receiving activity result method will be called after closing the camera * */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // if the result is capturing Image if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) { if (resultCode == RESULT_OK) { // successfully captured the image // launching upload activity launchUploadActivity(true); } else if (resultCode == RESULT_CANCELED) { // user cancelled Image capture Toast.makeText(getApplicationContext(), "User cancelled image capture", Toast.LENGTH_SHORT) .show(); } else { // failed to capture image Toast.makeText(getApplicationContext(), "Sorry! Failed to capture image", Toast.LENGTH_SHORT) .show(); } } else if (requestCode == CAMERA_CAPTURE_VIDEO_REQUEST_CODE) { if (resultCode == RESULT_OK) { // video successfully recorded // launching upload activity launchUploadActivity(false); } else if (resultCode == RESULT_CANCELED) { // user cancelled recording Toast.makeText(getApplicationContext(), "User cancelled video recording", Toast.LENGTH_SHORT) .show(); } else { // failed to record video Toast.makeText(getApplicationContext(), "Sorry! Failed to record video", Toast.LENGTH_SHORT) .show(); } } }
6- در ادامه نوبت به ساخت UploadActivity.java می رسد که کدش از قرار زیر است:
ارسال پاسخ