Android 拍照+选择本地图片

    技术2022-07-10  165

    拍照+选择本地图片

    首先创建xml文件如下:

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/take_photo" android:text="TAKE PHOTO"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/choose" android:text="choose_picture"/> <ImageView android:layout_gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/image"/> </LinearLayout>

    一个Butoon,用于点击拍照,另一个Button用于选择本地图片,ImageView用于显示照的图片。

    在Manifest加入文件的读写权限并在<application中添加一个provider如下,其中选择照片在现在的版本需要加入android:requestLegacyExternalStorage="true"具体原因可以去查阅资料:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:requestLegacyExternalStorage="true" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.cameraalbumtest.fileprovider2" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

    其中authorities中的值和接下来的Fileprovider,getUriForFile()方法的第二个参数必须保持一致,而name属性不同于之前,在更新后就更改为androidx.core.content.FileProvider。而meta-data指定了Uri的共享路径。

    在res资源文件中创建一个名为xml的Directory文件,并new一个名为file_paths的xm布局文件,修改其代码如下:

    <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path=""/> </paths>

    其中name属性可以随便填,而path是你指定的共享的具体路径,这里为空代表整个内存都可以共享。、

    接下来修改MainActivity代码:

    package com.example.choose_picture; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import android.Manifest; import android.annotation.TargetApi; import android.content.ContentUris; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.DocumentsContract; import android.provider.MediaStore; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final int CHOOSE_PHOTO = 2;//选择照片 private static final int TAKE_PHOTO = 1;//拍照 private ImageView imageView; private Button choose; private Button take_photo; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 实例化,并设立点击事件 */ choose = (Button)findViewById(R.id.choose); imageView = (ImageView)findViewById(R.id.image); take_photo = (Button)findViewById(R.id.take_photo); choose.setOnClickListener(this); take_photo.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.choose: //首先动态申请WRITE_EXTERNAL_STORAGE权限 if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission .WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(MainActivity.this,new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE},1); }else{ //权限申请成功就打开相册 openAlbum(); } break; case R.id.take_photo: //创建File 对象用于储存拍照之后的照片 File outputImage = new File(getExternalCacheDir(),"output_image.jpg"); try { if(outputImage.exists()){ outputImage.delete(); } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } if(Build.VERSION.SDK_INT >= 24 ){ //对Android的sdk进行判断,对Uri进行处理 //FileProvider.getUriForFile对内容进行封装保护,其三个参数为Content,任意字符串 // (provider中的authorities与其保持一致),File对象。 // imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalbumtest.fileprovider2",outputImage); }else{ imageUri = Uri.fromFile(outputImage); } //隐式Intent Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri); startActivityForResult(intent,TAKE_PHOTO); } } private void openAlbum() { Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent,CHOOSE_PHOTO);//打开相册 } /** * 重写onRequestPermissionsResult方法 * 对查看本地相册的权限申请进行判断看是否申请成功 * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 1: if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED ){ openAlbum();//申请成功 } else { Toast.makeText(this,"你拒绝了权限!",Toast.LENGTH_SHORT).show(); } break; default: } } /** * 对onActivityResult进行重写,对隐式活动的内容进行处理 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case CHOOSE_PHOTO: if(resultCode == RESULT_OK){ //对手机版本号进行判断对不同版本的手机进行不同的图片处理 if(Build.VERSION.SDK_INT >= 19){ handleImageOnKitkat(data); }else { handleImageBeforeKitkat(data); } } break; case TAKE_PHOTO: if(resultCode == RESULT_OK){ try { Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); imageView.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; default: break; } } /** * 进行封装的图片处理方式4.4以上 * @param data */ @TargetApi(19) private void handleImageOnKitkat(Intent data) { String imagePath = null; Uri uri =data.getData(); if(DocumentsContract.isDocumentUri(this,uri)){ //如果是Document类型的uri,则通过document id 进行处理 String docId = DocumentsContract.getDocumentId(uri); if("com.android.providers.media.documents".equals(uri.getAuthority())){ //如果Uri的Authority是media格式 String id = docId.split(":")[1];//解析出数字格式的id String selection = MediaStore.Images.Media._ID + "=" + id; imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection); }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){ Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); imagePath = getImagePath(contentUri,null); }else if("content".equalsIgnoreCase(uri.getScheme())){ //如果是content类的uri,则用普通方式进行处理,区别就是selection imagePath = getImagePath(uri,null); }else if("file".equalsIgnoreCase(uri.getScheme())){ //如果是file 类型的uri,就直接获取图片路径 imagePath = uri.getPath(); } //根据图片路径显示图片 disPlayImage(imagePath); } } /** * 没有进行封装的Uri的图片处理方式 * @param data */ private void handleImageBeforeKitkat(Intent data) { Uri uri =data.getData(); String imagePath = getImagePath(uri,null); disPlayImage(imagePath); } private String getImagePath(Uri uri, String selection) { String path = null; //通过Uri和seletion来获取图片的真实路径 Cursor cursor = getContentResolver().query(uri,null,selection,null,null); if(cursor != null){ if(cursor.moveToFirst()){ path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } cursor.close(); } return path; } /** * 显示图片: * 在Github上发现了解决方法,Android10以上版本, * 需要在AndroidManifest.xml中添加android:requestLegacyExternalStorage="true" * 加入这个权限后才能获取图 不然decodeFile返回值为null * @param imagePath */ private void disPlayImage(String imagePath) { if(imagePath != null){ //可以用不同的方法对图片进行压缩处理,这里没有多阐述 Bitmap bitmap = BitmapFactory.decodeFile(imagePath,null); imageView.setImageBitmap(bitmap); }else{ Toast.makeText(this,"获取图片失败",Toast.LENGTH_SHORT).show(); } } }

    其中注释比较详细,这里就不多做阐述。

    Processed: 0.040, SQL: 9