从相册或拍照更换图片功能的实现:(取图无裁剪功能)
获取图片方式: (类似更换头像的效果)
1、手机拍照 选择图片;
2、相册选取图片;
本文只是简单实现该功能,页面展示有些简陋,运行效果图如下:
创建xml布局文件(activity_main.xml ): 头部两个Button按钮,一个控制从相册选择照片,一个控制启动相册拍照选择图片。底部为一个ImageVIew,用于展示刚刚选择的图片。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45<?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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/btn_photo" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="@android:color/holo_red_light" android:text="相册选取" android:textColor="#FFF" android:textSize="16sp" /> <Button android:id="@+id/btn_camera" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_weight="1" android:background="@android:color/holo_red_light" android:text="拍照" android:textColor="#FFF" android:textSize="16sp" /> </LinearLayout> <!--展示选择的图片--> <ImageView android:id="@+id/image_show" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:layout_margin="6dp" /> </LinearLayout>
Android 4.4系统之前, 访问SD卡的应用关联目录需要声明权限的,从4.4系统开始不再需要权限声明。相关权限变成动态申请。
1<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第一部分:拍照获取图片
我们将拍照的图片放在SD卡关联缓存目录下。调用getExternalCacheDir()方法得到关联缓存目录, 具体的路径是/sdcard/Android/data/<package name>/cache。 那么为什么要使用应用关联缓目录来存放图片呢?因为从Android 6.0系统开始, 读写SD卡被列为了危险权限, 如果将图片存放在SD卡的任何其他目录, 都要进行运行时权限处理, 使用应用关联
目录则可以跳过这一步。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76** * 拍照 或 从相册获取图片 */ public class MainActivity extends AppCompatActivity { private Button btn_camera; private ImageView imageView; public static final int TAKE_CAMERA = 101; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_camera = (Button) findViewById(R.id.btn_camera); imageView = (ImageView) findViewById(R.id.image_show); //通过摄像头拍照 btn_camera.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建File对象,用于存储拍照后的图片 //存放在手机SD卡的应用关联缓存目录下 File outputImage = new File(getExternalCacheDir(), "output_image.jpg"); /* 从Android 6.0系统开始,读写SD卡被列为了危险权限,如果将图片存放在SD卡的任何其他目录, 都要进行运行时权限处理才行,而使用应用关联 目录则可以跳过这一步 */ try { if (outputImage.exists()) { outputImage.delete(); } } catch (Exception e) { e.printStackTrace(); } /* 7.0系统开始,直接使用本地真实路径的Uri被认为是不安全的,会抛 出一个FileUriExposedException异常。 而FileProvider则是一种特殊的内容提供器,它使用了和内 容提供器类似的机制来对数据进行保护, 可以选择性地将封装过的Uri共享给外部,从而提高了 应用的安全性 */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //大于等于版本24(7.0)的场合 imageUri = FileProvider.getUriForFile(MainActivity.this, "com.feige.pickphoto.fileprovider", outputImage); } else { //小于android 版本7.0(24)的场合 imageUri = Uri.fromFile(outputImage); } //启动相机程序 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //MediaStore.ACTION_IMAGE_CAPTURE = android.media.action.IMAGE_CAPTURE intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_CAMERA); } }); @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { switch (requestCode) { case TAKE_CAMERA: if (resultCode == RESULT_OK) { try { // 将拍摄的照片显示出来 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); imageView.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; default: break; } } }
从Android 7.0开始, 直接使用本地真实路径的Uri被认为是不安全的, 会抛出一个FileUriExposedException异常。 FileProvider则是一种特殊的内容提供器, 它使用了和内容提供器类似的机制来对数据进行保护, 可以选择性地将封装过的Uri共享给外部, 从而提高了应用的安全性。
首先要在AndroidManifest.xml中对内容提供器进行注册了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.feige.pickphoto"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application 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"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.feige.pickphoto.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> </manifest>
创建file_paths 资源文件:在res目录上右击——> new ——> Directory创建xml文件夹,然后在xml文件夹里新建file_paths.xml文件:
1
2
3
4
5
6
7
8
9<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!--external-path 就是用来指定Uri 共享的, name 属性的值可以随便填, path 属性的 值表示共享的具体路径。 这里设置 . 就表示将整个SD卡进行共享 --> <external-path name="my_images" path="." /> </paths>
第二部分:从相册获取图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117/** * 拍照 或 从相册获取图片 */ public class MainActivity extends AppCompatActivity { private Button choose_photo; private ImageView imageView; public static final int PICK_PHOTO = 102; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); choose_photo = (Button) findViewById(R.id.btn_photo); imageView = (ImageView) findViewById(R.id.image_show); //从相册选择图片 choose_photo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //动态申请获取访问 读写磁盘的权限 if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101); } else { //打开相册 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); //Intent.ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT" intent.setType("image/*"); startActivityForResult(intent, PICK_PHOTO); // 打开相册 } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { switch (requestCode) { case PICK_PHOTO: if (resultCode == RESULT_OK) { // 判断手机系统版本号 if (Build.VERSION.SDK_INT >= 19) { // 4.4及以上系统使用这个方法处理图片 handleImageOnKitKat(data); } else { // 4.4以下系统使用这个方法处理图片 handleImageBeforeKitKat(data); } } break; default: break; } } @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())) { 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,则使用普通方式处理 imagePath = getImagePath(uri, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) { // 如果是file类型的Uri,直接获取图片路径即可 imagePath = uri.getPath(); } // 根据图片路径显示图片 displayImage(imagePath); } /** * android 4.4以前的处理方式 * @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和selection来获取真实的图片路径 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; } private void displayImage(String imagePath) { if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath); imageView.setImageBitmap(bitmap); } else { Toast.makeText(this, "获取相册图片失败", Toast.LENGTH_SHORT).show(); } } }
共用拍照取图的FileProvider内容提供器。
*********完整MainActivity代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197import 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.provider.DocumentsContract; import android.provider.MediaStore; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import java.io.File; import java.io.FileNotFoundException; /** * 拍照 或 从相册获取图片 */ public class MainActivity extends AppCompatActivity { private Button choose_photo; private Button btn_camera; private ImageView imageView; public static final int TAKE_CAMERA = 101; public static final int PICK_PHOTO = 102; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); choose_photo = (Button) findViewById(R.id.btn_photo); btn_camera = (Button) findViewById(R.id.btn_camera); imageView = (ImageView) findViewById(R.id.image_show); //通过摄像头拍照 btn_camera.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建File对象,用于存储拍照后的图片 //存放在手机SD卡的应用关联缓存目录下 File outputImage = new File(getExternalCacheDir(), "output_image.jpg"); /** 从Android 6.0系统开始,读写SD卡被列为了危险权限,如果将图片存放在SD卡的任何其他目录, *都要进行运行时权限处理才行,而使用应用关联 目录则可以跳过这一步 */ try { if (outputImage.exists()) { outputImage.delete(); } } catch (Exception e) { e.printStackTrace(); } /** *7.0系统开始,直接使用本地真实路径的Uri被认为是不安全的,会抛 出一个FileUriExposedException异常。 *而FileProvider则是一种特殊的内容提供器,它使用了和内 容提供器类似的机制来对数据进行保护, *可以选择性地将封装过的Uri共享给外部,从而提高了 应用的安全性 */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //大于等于版本24(7.0)的场合 imageUri = FileProvider.getUriForFile(MainActivity.this, "com.feige.pickphoto.fileprovider", outputImage); } else { //小于android 版本7.0(24)的场合 imageUri = Uri.fromFile(outputImage); } //启动相机程序 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //MediaStore.ACTION_IMAGE_CAPTURE = android.media.action.IMAGE_CAPTURE intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_CAMERA); } }); //从相册选择图片 choose_photo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //动态申请获取访问 读写磁盘的权限 if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101); } else { //打开相册 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); //Intent.ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT" intent.setType("image/*"); startActivityForResult(intent, PICK_PHOTO); // 打开相册 } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { switch (requestCode) { case TAKE_CAMERA: if (resultCode == RESULT_OK) { try { // 将拍摄的照片显示出来 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); imageView.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; case PICK_PHOTO: if (resultCode == RESULT_OK) { // 判断手机系统版本号 if (Build.VERSION.SDK_INT >= 19) { // 4.4及以上系统使用这个方法处理图片 handleImageOnKitKat(data); } else { // 4.4以下系统使用这个方法处理图片 handleImageBeforeKitKat(data); } } break; default: break; } } @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())) { 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,则使用普通方式处理 imagePath = getImagePath(uri, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) { // 如果是file类型的Uri,直接获取图片路径即可 imagePath = uri.getPath(); } // 根据图片路径显示图片 displayImage(imagePath); } /** * android 4.4以前的处理方式 * @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和selection来获取真实的图片路径 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; } private void displayImage(String imagePath) { if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath); imageView.setImageBitmap(bitmap); } else { Toast.makeText(this, "获取图片失败", Toast.LENGTH_SHORT).show(); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持靠谱客。
最后
以上就是傻傻荷花最近收集整理的关于android实现拍照或从相册选取图片的全部内容,更多相关android实现拍照或从相册选取图片内容请搜索靠谱客的其他文章。
发表评论 取消回复