付出之完结一,0权限管理

在日常开发中,我们经常需要用到上传图片的
功能,这个时候通常有两种做法,第一种,从相机获取,第二种,从相册获取。今天这篇博客主要讲解利用系统的Intent怎样获取?

相机概述:

  • Android框架支持通过Camera API 或者Camera intent来抓取图像和视频

  • Camera
    此类是控制设备相机的主要API,此类用于创建相机应用时获取图片和视频

  • SurfaceView 此类为用户提供camera的实时图像预览

  • MediaRecorder 此类用于从camera录制视频

  • Intent
    一个MediaStore.ACTION_IMAGE_CAPTUREMediaStore.ACTION_VIDEO_CAPTURE的intent,可以使用它来抓取图像或者视频,而不能操作Camera对象

  • CameraPermission 你的应用必须请求使用设备相机的权限

<uses-permission android:name="android.permission.CAMERA"/>
  • CameraFeatures 你的应用必须也要声明要使用的相机特性

    <uses-feature android:name=”android.hardware.camera”
    android:required=”false”/>
    <uses-permission
    android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>

    <!--在使用视频捕获设备来录制视频的时候,你的应用必须有一下的权限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    
  • 使用现有的相机应用
    一个不用写代码来获取图片和视频的快速方法是使用intent来调用现有的android
    camera应用,一个camera intent调用现存的相机应用抓取图片
    或者视频剪辑然后返回你的应用

  • 调用一个相机的intent 主要有一下的步奏

  • (1)组件一个相机intent 创建一个请求图片或者视频的intent
    使用以下intent类型中的一个

MediaStore.ACTION_IMAGE_CAPTURE从已存在的相机应用中请求一个图片
MediaStore.ACTION_VIDEO_CAPTURE,从已存在的相机应用中请求一个视频

  • (2)启动这个相机的intent,使用startActivityForResult()方法来执行相机intent,在你启动intent后,相机应用的界面会出现在设备屏幕上,然后用户就可以yoga他来获取图片和视频

  • (3)接收intent结果,在你的应用中设置一个onActivityResult()方法来接收从相机intent来的回调和数据,当用户获取了一个图片或者视频之后(或者取消了操作)系统就会调用此方法。

  • 图像或者intent

private static final int MEDIA_TYPE_IMAGE = 1;
private static final int MEDIA_TYPE_VIDEO = 2;

             public static Uri getOutputMediaFileUri(int type) {
        return Uri.fromFile(getOutputMediaFile(type));
    }


    private static File getOutputMediaFile(int type) {
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp");
        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                return null;
            }
        }
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File medifFile = null;
        if (type == MEDIA_TYPE_IMAGE) {
            medifFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
        } else if (type == MEDIA_TYPE_VIDEO) {
            medifFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".avi");
        } else {
            return null;
        }

        return medifFile;
    }
  • 当startActivityForResult()方法被执行,看到一个相机应用的界面
    当用户获取了一个图像(或者取消了操作)用户界面返回到你的应用
    你必须拦截onActivityResult()方法来接收intent的结果然后在继续执行你的应用

/**
* 拍照的方法
*/
private void imageCamera() {
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
getOutputMediaFileUri(MEDIA_TYPE_IMAGE));
startActivityForResult(intent, MEDIA_TYPE_IMAGE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (resultCode) {
        case RESULT_OK:
            //图片
            if (MEDIA_TYPE_IMAGE == requestCode) {
                Log.d("CameryActivity", "mFile:" + mFile);
            } else if (MEDIA_TYPE_VIDEO == requestCode) {
                //视频
            }

            break;
    }
}
  • 视频获取inten
    使用相机intent获取视频是使用最少代码使得你的应用获取视屏的捷径
    一个视频获取intent可以包含以下额外的信息
  • (1)MediaStore.EXTRA_OUTPUT此设置需要一个保存视频的路径和文件名的Uri,此设置是可选的但强烈推荐,如果你不指定此值,相机应用就把请求到的图像以默认的文件名保存到默认的文件夹下,这些信息保存在返回的intent的Intent.getData()字段中
  • (2)MediaStore.EXTRA_VIDEO_QUALITY
    此值在最低质量最小文件尺寸时是0,在最高质量最大文件尺寸时是1
  • (3)MediaStore.EXTRA_DURATION_LIMIT
    此值设置获取视屏的长度,以秒为单位
  • (4)MediaStore.EXTRA_SIZE_LIMIT
    此值设置获取视屏文件的大小,以字节为单位

 /**
         * 录视频
         */
        private void videoCamera() {
            Intent intent = new Intent();
            intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, getOutputMediaFileUri(MEDIA_TYPE_VIDEO));
            intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);  //设置视频质量
            startActivityForResult(intent, MEDIA_TYPE_VIDEO);
        }
  • 音频录制步奏:

    android为我们提供了android.media.MediaRecorder类用于音频的录制。
    
  • 1、创建android.media.MediaRecorder实例

  • 2、设置音源MediaRecorder.setAudioSource(),通过可以是MediaRecorder.AudioSource.MIC

  • 3、设置输出文件的格式 MediaRecorder.setOutputFormat()\

  • 4、设置输出文件 MediaRecorder.setOutputFile()

  • 5、设置音频编码 MediaRecorder.setAudioEncoder()

  • 6、设置MediaRecorder.prepare()

  • 7、调用MediaRecorder.start()开始录制

  • 8、调用MediaRecorder.stop()停止录制

  • 9、完成或者结束录制调用MediaRecorder.release()来释放资源

  • 录音代码:

public class RecodeActivity extends AppCompatActivity implements
View.OnClickListener, MediaRecorder.OnErrorListener {

private Button startRecord;
private Button stopRecord;
private MediaRecorder mRecorder;
private boolean prepared = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recode);
    mRecorder = new MediaRecorder();
    initialize();
}

private void initialize() {

    startRecord = (Button) findViewById(R.id.startRecord);
    startRecord.setOnClickListener(this);
    stopRecord = (Button) findViewById(R.id.stopRecord);
    stopRecord.setOnClickListener(this);
    initRecord();
}


@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.startRecord:
            startRecord();
            break;
        case R.id.stopRecord:
            stopRecord();
            break;
    }
}

/**
 * 初始化录音的准备工作
 */
private void initRecord() {
    mRecorder.reset();
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);  //设置音源
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //设置输出格式
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //设置音频的编码格式
    String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + File.separator + System.currentTimeMillis() + ".mp3";
    mRecorder.setOutputFile(path);  //设置输出文件夹
    try {
        mRecorder.prepare();
        prepared = true;
    } catch (IOException e) {
        e.printStackTrace();
    }

    stopRecord.setEnabled(false);

}

/**
 * 停止录音
 */
private void stopRecord() {
    if (prepared) {
        mRecorder.start();
        stopRecord.setEnabled(true);
        startRecord.setEnabled(false);
        prepared = false;
    }
}

/**
 * 开始录音
 */
private void startRecord() {
    mRecorder.stop();
    stopRecord.setEnabled(false);
    startRecord.setEnabled(true);
}


@Override
public void onError(MediaRecorder mr, int what, int extra) {
    mRecorder.reset();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mRecorder != null) {
        mRecorder.release();
    }
}

}

一、      Android Camera实现方式

Android提供两种实现方式给开发员来实现拍照功能:Camera
API和Camera Intent.下面的章节主要是讲解如何使用Camera
Intent进行Camera开发.

主要内容如下

WebView的参数设置:

  • 加载网页
  • 加载本地
  • post方式传递参数

String postData = "clientID = cid & usernaem = name";
webView.postUrl(String url,byte[]postData) //加载网页使用post方法,

//使用loadData()方法来加载html的数据
loadData()方法需要三个参数:HTML TAG,MIME类型(text/html,网页编码方式(utf-8)
wv.loadData(content,"text/html","utf-8");
Camera Intent

通过”Camera
Intent”方式可以快速,方便以及更少的代码来完成Camera功能.其通过Android的Intent调用系统现有的Camera应用程序来实现此功能.并实现”onActivityResult()”获取并处理拍照返回的结果.

调用Camera
Intent流程主要分为如下几个步骤:

    构建一个Camera
Intent来向Android系统请求图片和视频

    MediaStore.ACTION_IMAGE_CAPTURE 请求图像

    MediaStore.ACTION_VIDEO_CAPTURE 请求视频

    启动Camera Intent

    使用startActivityForResult()方法启动Camera
Intent

    接收Camera
Intent返回的结果

    创建onActivityResult()方法接收回调和返回图像数据

  • 怎样通过相机获取我们的图片
  • 怎样启动相册获取我们想要的图片
  • 在Android 6.0中的动态权限处理】
  • 调用系统Intent和自定义相册的优缺点对比
图像拍照意图(Image capture intent)

       首先来看一下Demo的运行效果图,具体操作是点击”Take
Photo!”按钮打开系统自带的Camera界面,拍摄完毕后将拍摄的照片显示ImageView中.

图片 1

开发步骤:

A.     新建一个Android项目,取名为”CameraIntentDemo”.

图片 2

B.      构建主界面元素.

main.xml文件内容如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

 

    <TextView

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/hello" />

 

    <Button

        android:id="@+id/btnTakePhoto"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Take Photo!" />

 

    <ImageView

        android:id="@+id/imgvTakePhoto"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        android:background="#FFFFFF"/>

 

</LinearLayout>

C.      使用Intent来启动Camera功能.

首先声明一个Intent,并以MediaStore.ACTION_IMAGE_CAPTURE实例化该Intent.

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

然后设置Intent的MediaStore.EXTRA_OUTPUT属性可以将拍摄的图像保存到指定路径.

//
set the image file name

intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

最后调用startActivityForResult方法来启动系统的Camera功能.

D.     捕获系统Camera的回调

重写onActivityResult()方法,通过requestCode参数可以知道是否Camera
Intent的Result,然后再根据Intent参数对接收到图像数据进行处理或者保存.如果通过

MediaStore.EXTRA_OUTPUT属性自动将图像数据保存到指定的位置,那么在

onActivityResult()得到的Intent的数据是为NULL的.这一点大家需要注意一下.

E.      在AndroidManifest.xml添加访问SD权限声明.

<!– 在SDCard中创建与删除文件权限 –>

    <uses-permission android:name=“android.permission.MOUNT_UNMOUNT_FILESYSTEMS” />

    <!– 往SDCard写入数据权限 –>

    <uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE” />

CameraIntentDemoActivity.java文件内容:

public class CameraIntentDemoActivity extends Activity {

   

    private static final int MEDIA_TYPE_IMAGE = 1;

    private static final int MEDIA_TYPE_VIDEO = 2;  

    private Uri fileUri;

   

    private static Uri getOutputMediaFileUri(int type) {

       return Uri.fromFile(getOutputMediaFile(type));

    }

   

    private static File getOutputMediaFile(int type){

        // To be safe, you should check that the SDCard is mounted

        // using Environment.getExternalStorageState() before doing this.

 

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp");

        // This location works best if you want the created images to be shared

        // between applications and persist after your app has been uninstalled.

 

        // Create the storage directory if it does not exist

        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;

        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;

    }

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        Button btnTakePhoto = (Button)this.findViewById(R.id.btnTakePhoto);

        btnTakePhoto.setOnClickListener(new View.OnClickListener() {

          

           @Override

           public void onClick(View v) {

              Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

              // create a file to save the image

              fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

              // set the image file name

              cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

              // start the image capture Intent

              startActivityForResult(cameraIntent, 0);

           }

       });

       

    }

 

    @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

       try {

           if (requestCode != 0) {

              return;

           }

           Bitmap bmp = null;

           super.onActivityResult(requestCode, resultCode, data);

           if (data != null) {

              Bundle extras = data.getExtras();

              bmp = (Bitmap)extras.get("data");            

           }

           else {

              FileInputStream fis = new FileInputStream(fileUri.getPath());

              bmp = BitmapFactory.decodeStream(fis);

           }

          

           ImageView imag = (ImageView)this.findViewById(R.id.imgvTakePhoto);

           imag.setImageBitmap(bmp);

          

          

       } catch (Exception e){

           System.out.println(e.getMessage());

       }

      

    }

}

总共有两种方式,

视频拍摄意图(Video capture intent)

       使用Camera
Intent同样可以快速,方便以及更少代码实现视频拍摄.它还支持多种扩展特性.

•     
MediaStore.EXTRA_OUTPUT – 设置视频输出位置.

•     
MediaStore.EXTRA_VIDEO_QUALITY
– 设置视频质量,0为最差,1为最清晰.

•     
MediaStore.EXTRA_DURATION_LIMIT – 设置视频的限制长度.

•     
MediaStore.EXTRA_SIZE_LIMIT – 设置视频的限制大小.

 

开发步骤:

A.    新建一个Android
Project命名为VideoIntentDemo,指定最低版本号.

图片 3

B.    构建界面元素

同样是放置一个Button来触发视频拍摄,下面放置一个TextView用来存放返回信息.

界面布局:

图片 4

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

 

    <TextView

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/hello" />

 

    <Button

        android:id="@+id/btTakeVideo"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Take Video" />

   

    <TextView

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:background="#FFFFFF"

        android:id="@+id/tvActivityResult"

        android:minLines="5"

        />

 

</LinearLayout>

C.    代码实现

首先声明一个Uri对象用来保存视频文件保存的路径.

private Uri fileUri;

然后实现Video功能代码.

//
create new Intent

Intent intent
new Intent(MediaStore.ACTION_VIDEO_CAPTURE); 

//
create a file to save the video

fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);

//
set the video file name

intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

//
set the video image quality to high

intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); 

//
start the Video Capture Intent

startActivityForResult(intent,
1);

 

VideoIntentDemoActivity.java文件内容:

public class VideoIntentDemoActivity extends Activity {

   

    private Uri fileUri;

   

    private static final int MEDIA_TYPE_IMAGE = 1;

    private static final int MEDIA_TYPE_VIDEO = 2;

   

    private static Uri getOutputMediaFileUri(int type) {

       return Uri.fromFile(getOutputMediaFile(type));

    }

   

    private static File getOutputMediaFile(int type){

        // To be safe, you should check that the SDCard is mounted

        // using Environment.getExternalStorageState() before doing this.

 

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp");

        // This location works best if you want the created images to be shared

        // between applications and persist after your app has been uninstalled.

 

        // Create the storage directory if it does not exist

        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;

        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;

    }

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        Button btnTakeVideo = (Button)this.findViewById(R.id.btTakeVideo);

       btnTakeVideo.setOnClickListener(new View.OnClickListener() {

          

           @Override

           public void onClick(View v) {

              // create new Intent

              Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

 

              // create a file to save the video

              fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);

              // set the video file name

              intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

              // set the video image quality to high

               intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);

 

              // start the Video Capture Intent

              startActivityForResult(intent, 1);

           }

       });

    }

   

    @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    TextView tvVideo = (TextView)this.findViewById(R.id.tvActivityResult);

    try {        

           if (requestCode == 1) {           

              tvVideo.setText("视频保存成功,路径为:" + fileUri.getPath());

           }

           super.onActivityResult(requestCode, resultCode, data);

       } catch (Exception e) {

           tvVideo.setText(e.getLocalizedMessage());       

       }

    }

}

D.    在AndroidManifest.xml添加访问SD权限声明.

<!– 在SDCard中创建与删除文件权限 –>

<uses-permission android:name=“android.permission.MOUNT_UNMOUNT_FILESYSTEMS” />

<!– 往SDCard写入数据权限 –>

<uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE” />

 

最后附上源码下载:

第一种方式:

第一步,通过 MediaStore.ACTION_IMAGE_CAPTURE 启动我们的相机

Intent pIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//调用摄像头actionstartActivityForResult(pIntent, INTENT_CODE_IMAGE_CAPTURE1);//requestcode

第二步,在onActivityResult进行处理,,核心代码如下

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case INTENT_CODE_IMAGE_CAPTURE1: if (resultCode == RESULT_OK) { Bundle pBundle = data.getExtras(); //从intent对象中获取数据, if (pBundle != null) { Bitmap pBitmap =  pBundle.get; if (pBitmap != null) { mIv.setImageBitmap; } } } break;}

第二种 方式

第一步,通过 MediaStore.ACTION_IMAGE_CAPTURE 启动相机,并指定
MediaStore.EXTRA_OUTPUT ,intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile; 传入我们的URI,这样,最终返回的信息会存储在我们的mFile中。

private void startCameraWithHighBitmap() { //确定存储拍照得到的图片文件路径 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { mFile = new File(Environment.getExternalStorageDirectory(), getName; } else { Toast.makeText(this, "请插入sd卡", Toast.LENGTH_SHORT).show(); return; } try { mFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); //加载Uri型的文件路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile; //向onActivityResult发送intent,requestCode为INTENT_CODE_IMAGE_CAPTURE2 startActivityForResult(intent, INTENT_CODE_IMAGE_CAPTURE2);}

第二步:在onActivityResult进行处理,并对图片进行相应的压缩,防止在大图片的情况下发生OOM

case INTENT_CODE_IMAGE_CAPTURE2: if (resultCode == RESULT_OK) { Bitmap bitmap = ImageZip.decodeSampledBitmapFromFile(mFile.getAbsolutePath(), mWidth, mHeight); mIv.setImageBitmap; } break;

 public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(pathName, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; Bitmap src = BitmapFactory.decodeFile(pathName, options);// return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize); return src; } private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // 源图片的高度和宽度 final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize;}

两种方法的区别

第一种方法获取的bitmap是被缩放的bitmap,第二种方法获取的bitmap是完整的bitmap,实际使用中根据需求情况决定使用哪一种方法。

官网参考地址

第一步,通过 Intent.ACTION_GET_CONTENT
这个Intent,并设置相应的type,启动相册。

Intent i = new Intent(Intent.ACTION_GET_CONTENT, null);i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");startActivityForResult(i, INTENT_CODE_IMAGE_GALLERY1);

第二步,在onActivityResult中对返回的uri数据进行处理

  • 需要注意的是:这里我们需要注意是不是MIUI系统,如果不是MIUI系统,我们只需要进行一下处理,就OK了

private void setPhotoForNormalSystem(Intent data) { String filePath = getRealPathFromURI(data.getData; Bitmap bitmap = ImageZip.decodeSampledBitmapFromFile(filePath, mWidth, mHeight); mIv.setImageBitmap;}/** * 解析Intent.getdata()得到的uri为String型的filePath * * @param contentUri * @return */public String getRealPathFromURI(Uri contentUri) { String[] proj = {MediaStore.Audio.Media.DATA}; Cursor cursor = managedQuery(contentUri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index);}
  • 如果是MIUI系统,我们需要进行一下处理

private void setPhotoForMiuiSystem(Intent data) { Uri localUri = data.getData(); String scheme = localUri.getScheme(); String imagePath = ""; if ("content".equals { String[] filePathColumns = {MediaStore.Images.Media.DATA}; Cursor c = getContentResolver().query(localUri, filePathColumns, null, null, null); c.moveToFirst(); int columnIndex = c.getColumnIndex(filePathColumns[0]); imagePath = c.getString(columnIndex); c.close(); } else if ("file".equals {//小米4选择云相册中的图片是根据此方法获得路径 imagePath = localUri.getPath(); } Bitmap bitmap = ImageZip.decodeSampledBitmapFromFile(imagePath, mWidth, mHeight); mIv.setImageBitmap;}

在代码中的体现如下,即判断是否是MIUI系统,对于不同的系统采用不同的方法

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != RESULT_OK) { return; } switch (requestCode) { case INTENT_CODE_IMAGE_GALLERY1: if (SystemUtils.isMIUI { setPhotoForMiuiSystem; } else { setPhotoForNormalSystem; } break; }}

我们知道在Android6.0以上的系统,有一些权限需要动态授予

group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTSgroup:android.permission-group.PHONE permission:android.permission.READ_CALL_LOG permission:android.permission.READ_PHONE_STATE permission:android.permission.CALL_PHONE permission:android.permission.WRITE_CALL_LOG permission:android.permission.USE_SIP permission:android.permission.PROCESS_OUTGOING_CALLS permission:com.android.voicemail.permission.ADD_VOICEMAILgroup:android.permission-group.CALENDAR permission:android.permission.READ_CALENDAR permission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERA permission:android.permission.CAMERAgroup:android.permission-group.SENSORS permission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATION permission:android.permission.ACCESS_FINE_LOCATION permission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGE permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONE permission:android.permission.RECORD_AUDIOgroup:android.permission-group.SMS permission:android.permission.READ_SMS permission:android.permission.RECEIVE_WAP_PUSH permission:android.permission.RECEIVE_MMS permission:android.permission.RECEIVE_SMS permission:android.permission.SEND_SMS permission:android.permission.READ_CELL_BROADCASTS

我们这里容易
得知读取相机需要的权限有,写sd卡权限,读取camera权限,这两个权限都需要动态授予。

这里我们以检查是否授予camera权限为例子讲解

第一步,在启动相机的时候检查时候已经授予camera权限,没有的话
,请求camera权限

if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {//还没有授予权限 if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { Toast.makeText(this, "您已禁止该权限,需要重新开启。", Toast.LENGTH_SHORT).show(); } else { ActivityCompat.requestPermissions(this, new String[]{permission}, request_camera2); }}else{// 已经授予权限 startCameraWithHighBitmap();}private void startCameraWithHighBitmap() { //确定存储拍照得到的图片文件路径 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { mFile = new File(Environment.getExternalStorageDirectory(), getName; } else { Toast.makeText(this, "请插入sd卡", Toast.LENGTH_SHORT).show(); return; } try { mFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); //加载Uri型的文件路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile; //向onActivityResult发送intent,requestCode为INTENT_CODE_IMAGE_CAPTURE2 startActivityForResult(intent, INTENT_CODE_IMAGE_CAPTURE2);}

第二步:重写onRequestPermissionsResult方法,判断是否授权成功,成功的话启动相机,核心代码如下。

@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case request_camera2: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { startCameraWithHighBitmap(); } else { // Permission Denied Toast.makeText(this, "Permission Denied", Toast .LENGTH_SHORT).show(); } break; }}

至于检查sd卡写权限的,这里不再阐述,有兴趣的话,可以下载源码看一下。

关于Android6.0动态获取权限的,可以参考这一篇博客在Android 6.0
设备上动态获取权限

调用系统Intent启动相册

优点: 代码简洁

缺点:对于不同的手机厂商,room往往被修改了,有时候调用系统的Intent,会有一些一项不到的bug,
不能实现多张图片的选择

自定义相册

优点: 实现的样式可以自己定制,可以实现多张图片的选择等

缺点: 代码量稍微多一些

总结

综上所述,对于本地相册的功能,本人还是强烈推荐自己实现,因为采用系统的,灵活性差,更重要的是,经常会有一些
莫名其妙的bug

这里给大家推荐两种实现方式,一个是鸿洋大神以前写的,一个是GitHub的开源库。

Android 超高仿微信图片选择器 图片该这么加载

Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等

android-multiple-images-selector

关于裁剪图片的Intent,网上的大多数做法是

public static Intent cropPic(Uri imageUri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.putExtra("crop", "true"); // 设置x,y的比例,截图方框就按照这个比例来截 若设置为0,0,或者不设置 则自由比例截图 intent.putExtra("aspectX", 2); intent.putExtra("aspectY", 1); // 裁剪区的宽和高 其实就是裁剪后的显示区域 若裁剪的比例不是显示的比例, // 则自动压缩图片填满显示区域。若设置为0,0 就不显示。若不设置,则按原始大小显示 intent.putExtra("outputX", 200); intent.putExtra("outputY", 100); // 不知道有啥用。。可能会保存一个比例值 需要相关文档啊 intent.putExtra("scale", true); // true的话直接返回bitmap,可能会很占内存 不建议 intent.putExtra("return-data", false); // 上面设为false的时候将MediaStore.EXTRA_OUTPUT即"output"关联一个Uri intent.putExtra("output", imageUri); // 看参数即可知道是输出格式 intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString; // 面部识别 这里用不上 intent.putExtra("noFaceDetection", false); return intent;}

当你运行代码的时候,部分设备会报错,大致的意思是:com.android.camera.action.CROP
的Activity not found

解决方法,我们可以捕获一下异常,防止发生崩溃,并弹出吐司提醒用户不支持裁剪功能。

try{ Intent intent = IntentUtils.cropPic(Uri.fromFile; startActivityForResult(intent,req_crop);}catch(ActivityNotFoundException a){ String errorMessage = "Your device doesn't support the crop action!"; Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT); toast.show();}

当然,github上面有两个比较好的开源库

android-crop

cropper

文章首发地址CSDN:

源码下载地址:

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注