一开始的思路是这一块的功能单独出去;这样处理又会碰见很多问题.
还是集成在Activity中可能效果更好些,
而且三星的手机调用系统相机会导致调用的Activity会重启生命周期,如果是在fragment中调用的,会碰见更多的问题,做外包的伤不起,想深入下这个问题都没时间,暂时记录下在Activity中解决问题的方法,方便后面使用时直接拿来用.
比如在Activity中点击某个按钮,弹出一个对话框,选择拍照还是选择图片
mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { final CharSequence[] items = { "相册", "拍照", "取消" }; dlg = new AlertDialog.Builder(RenZhengZPActivity.this) .setTitle("选择图片") .setItems( items, new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int item) { // 这里item是根据选择的方式, // 在items数组里面定义了两种方式,拍照的下标为1所以就调用拍照方法 if (item == 1) { toGetPic(); } else if (item == 0) { // toTakePhoto(); toGallery(); } else if (item == 2) { dlg.dismiss(); } } } ).create(); dlg.show(); } } );
在Activity中的2个跳转到系统相机和系统相册的方法
/** * 跳转到系统相册, */ private void toGallery() { Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, 1); //采用下面被注释掉的方法去访问系统相册功能,在Nexus5上会导致崩溃 // Intent getImage = new Intent(Intent.ACTION_GET_CONTENT); // getImage.addCategory(Intent.CATEGORY_OPENABLE); // getImage.setType("image/jpeg"); // startActivityForResult(getImage, 1); } /**跳转到系统相机,同时指定保存的拍照图片的位置 */ private void toGetPic() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 下面这句指定调用相机拍照后的照片存储的路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File( Environment.getExternalStorageDirectory(), "xiaoma.jpg"))); startActivityForResult(intent, 2); }
复写Activity 的onActivityResult方法:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { // 如果是直接从相册获取 case 1: Log.i(TAG, "相册获取图片之后回到RenZhengZPActivity,并启动裁剪"); if (data != null) { startPhotoZoom(data.getData()); } break; // 如果是调用相机拍照时 case 2: Log.i(TAG, "调用相机拍照获取图片之后回到RenZhengZPActivity,并启动裁剪"); File temp = new File(Environment.getExternalStorageDirectory() + "/xiaoma.jpg"); startPhotoZoom(Uri.fromFile(temp)); break; // 取得裁剪后的图片 case 3: Log.i(TAG, "裁剪图片之后,获取图片路径,并添加到集合中"); if (data != null) { setPicToView(data); } break; default: break; } super.onActivityResult(requestCode, resultCode, data); }
调用系统的裁剪功能:
/** * 裁剪图片方法实现 * * @param uri */ public void startPhotoZoom(Uri uri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 200); intent.putExtra("outputY", 200); intent.putExtra("return-data", true); startActivityForResult(intent, 3); }
保存得到裁剪之后的图片
/** * 保存裁剪之后的图片数据 * * @param picdata */ private void setPicToView(Intent picdata) { Bundle extras = picdata.getExtras(); if (extras != null) { photo = extras.getParcelable("data"); // 写到SD卡里面,photo就是个流数据: 创建一个文件夹写到SD卡后,创建个集合,保存所有图片路径 // 3.写到SD卡中,把路径获取到,传过去 String path = Environment.getExternalStorageDirectory() + "/project/"; String photoName = Tools.createFileName(); // 把bitmap以文件路径形式保存到sd卡上 Tools.savePhotoToSDCard(path, photoName, photo); Log.i(TAG, "照片的路径名称:" + path + "/" + photoName); //TODO 得打照片路径之后的处理 } }
Tools中的方法:
/** * 获取当前时间给不同文件命名 * @return */ public static String createFileName() { String fileName = ""; Date date = new Date(System.currentTimeMillis()); // 系统当前时间 SimpleDateFormat dateFormat = new SimpleDateFormat( "'IMG'_yyyyMMdd_HHmmss"); fileName = dateFormat.format(date) + ".jpg"; return fileName; }
/** * 将Bitmap 以文件路径形式保存到SD卡上,取出时直接用这个文件路径就行了。 * 拿到文件路径就可以File file = new File(文件路径),然后就可以把这个File上传服务器 * @param path * @param photoName * @param photoBitmap */ public static void savePhotoToSDCard(String path, String photoName, Bitmap photoBitmap) { if (android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) { File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } File photoFile = new File(path, photoName); //在指定路径下创建文件 System.out.println(photoFile); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(photoFile); System.out.println(photoFile+"................................"); if (photoBitmap != null) { if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) { fileOutputStream.flush(); } } } catch (FileNotFoundException e) { photoFile.delete(); e.printStackTrace(); } catch (IOException e) { photoFile.delete(); e.printStackTrace(); } finally { try { if(fileOutputStream!=null){ fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } photoBitmap.recycle(); } } }
另外,在调用系统的拍照或者相册之后,如果不需要调用裁剪,也可以直接拿到intent.getData(),可以拿到图片在android系统中的uri,通过uri也可以拿到图片
/** * 在Activity 的 onActivityResult() 中调用 本方法, 如果是从相册选取的照片, * 调用本方法, 获取照片的的路径 * @param activity * @param data * @return */ public static String loadImgFromGallery(Activity activity, Intent data) { if(data == null){ return null; } if (bitMap != null) { bitMap.recycle(); } // 外界的程序访问ContentProvider所提供数据 可以通过ContentResolver接口 ContentResolver resolver = activity.getContentResolver(); // 此处的用于判断接收的Activity是不是你想要的那个 try { Uri originalUri = data.getData(); // 获得图片的uri // 显得到bitmap图片 //TODO Bitmap bitmap = getThumbnail(Uri uri,int size); // 这里开始的第二部分,获取图片的路径: String[] proj = { MediaStore.Images.Media.DATA }; // 好像是android多媒体数据库的封装接口,具体的看Android文档 Cursor cursor = activity.managedQuery(originalUri, proj, null, null, null); // 按我个人理解 这个是获得用户选择的图片的索引值 int column_index = cursor .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); // 将光标移至开头 ,这个很重要,不小心很容易引起越界 cursor.moveToFirst(); return cursor.getString(column_index); } catch (IOException e) { e.printStackTrace(); } return null; }
通过uri 拿取到图片bitmap对象
(方法来源:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0826/1665.html)
/** * size 宽和高的最大值 */ public static Bitmap getThumbnail(Uri uri,int size) throws FileNotFoundException, IOException{ //通过uri拿取到输入流 InputStream input = this.getContentResolver().openInputStream(uri); //拿到Option对象, 设置一些优化的属性 BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options(); onlyBoundsOptions.inJustDecodeBounds = true; onlyBoundsOptions.inDither=true;//optional onlyBoundsOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional BitmapFactory.decodeStream(input, null, onlyBoundsOptions);//从输入流中解码图片,得到图片的option input.close();//关闭输入流 if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)){ return null; } int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;//取款高的最大值 //得到给定的大小和原始大小的比值 double ratio = (originalSize > size) ? (originalSize / size) : 1.0; BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio); bitmapOptions.inDither=true;//optional bitmapOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional input = this.getContentResolver().openInputStream(uri);//再次得到输入流 //根据缩放后的Option得到bitmap Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions); input.close(); return bitmap; } private static int getPowerOfTwoForSampleRatio(double ratio){ int k = Integer.highestOneBit((int)Math.floor(ratio)); if(k==0) return 1; else return k; }
拍照返回时,因为已经制定了保存相片的地址,所以直接通过地址在sd卡下拿到图片就行了
通过地址拿取图片的方法
/** * 加载本地图片, 略缩图 * @param imgPath * @return */ public static Bitmap getLoacalBitmap(String imgPath) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; options.inPurgeable = true; options.inInputShareable = true; FileInputStream fis = null; try { fis = new FileInputStream(imgPath); } catch (IOException e) { e.printStackTrace(); } return BitmapFactory.decodeStream(fis, null, options); }
另外一个写的比较好的调用系统相机的博文:(膜拜下)
http://blog.csdn.net/a497393102/article/details/8949727