安卓开发之Intent系统调用系统相机Camera(中软杯项目)
文章目錄
- 出現了FileUriExposedException
- 原因:
- 出現了動態權限問題
- 原因:
- 動態申請權限博客
- 解決了權限問題,但是拍照沒法顯示于imageview
- 原因
- 誤點拍照后返回程序崩潰:
- 原因
- 誤點相冊后返回程序崩潰:
- 原因
- 有些型號的手機BitmapFactory.decodeFile獲取Bitmap為空
- 原因
- 測試
寫完之后,一點就閃退,調試后,原因如下:
出現了FileUriExposedException
2021-05-09 15:50:12.100 1727-1727/com.example.software_china E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.example.software_china, PID: 1727android.os.FileUriExposedException: file:///storage/emulated/0/1620546589434.jpg exposed beyond app through ClipData.Item.getUri()at android.os.StrictMode.onFileUriExposed(StrictMode.java:1978)at android.net.Uri.checkFileUriExposed(Uri.java:2371)at android.content.ClipData.prepareToLeaveProcess(ClipData.java:963)at android.content.Intent.prepareToLeaveProcess(Intent.java:10331)at android.content.Intent.prepareToLeaveProcess(Intent.java:10316)at android.app.Instrumentation.execStartActivity(Instrumentation.java:1667)at android.app.Activity.startActivityForResult(Activity.java:4762)at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:675)at android.app.Activity.startActivityForResult(Activity.java:4691)at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:662)at com.example.software_china.MainActivity$1.onClick(MainActivity.java:48)at android.view.View.performClick(View.java:6724)at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)at android.view.View.performClickInternal(View.java:6682)at android.view.View.access$3400(View.java:797)at android.view.View$PerformClick.run(View.java:26479)at android.os.Handler.handleCallback(Handler.java:873)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:242)at android.app.ActivityThread.main(ActivityThread.java:7227)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:499)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:962)總之呢,就是FileUriExposedException報錯
原因:
對于面向 Android 7.0 的應用,Android 框架執行的 StrictMode API 政策禁止在應用外部公開 file:// URI , 如果一項包含文件 URI 的 intent 離開應用,則應用出現故障,并出現 FileUriExposedException 異常(需要把它封裝一下)
然后改成
出現了動態權限問題
package com.example.software_china;import android.Manifest; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.widget.ImageView;import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;import java.io.File;public class MainActivity extends AppCompatActivity {private Button bt_camera;private Button bt_show_imag;private ImageView iv_image;int writeflag = 0;//判斷儲存權限是否獲取public void openCamera() {Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());startActivityForResult(intent,100);}public Uri getImageUri() {Uri imageUri;File file=new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}String path = file.getPath();if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {imageUri = Uri.fromFile(file);} else {//兼容android7.0 使用共享文件的形式ContentValues contentValues = new ContentValues(1);contentValues.put(MediaStore.Images.Media.DATA, path);imageUri = this.getApplication().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);}return imageUri;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bt_camera=(Button) findViewById(R.id.bt_camera);iv_image =(ImageView) findViewById(R.id.iv_image);bt_show_imag =(Button) findViewById(R.id.bt_show_imag);bt_camera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions((Activity) MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);} else {openCamera();}}});bt_show_imag.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(Intent.ACTION_VIEW);intent.setDataAndType(getImageUri(),"image/*");startActivity(intent);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if(requestCode==100){iv_image.setImageURI(getImageUri());}} }原因:
動態申請權限博客
Android 6.0 以后為了保護用戶隱私,將一些權限的申請放在了應用運行的時候去申請, 比如以往的開發中,開發人員只需要將需要的權限在清單文件中配置即可,現在Google 可能想到用戶可能并不注意這些權限。 so~ 就迎來了動態權限機制。
請注意,如果你使用了API 23以上, 然而并沒有用代碼處理權限問題。 那么你的程序將會 CRASH !!!
下面我們來看看到底哪些權限是需要動態申請的, 也稱為危險權限。
group:android.permission-group.CONTACTSpermission:android.permission.WRITE_CONTACTSpermission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTSgroup:android.permission-group.PHONEpermission:android.permission.READ_CALL_LOGpermission:android.permission.READ_PHONE_STATE permission:android.permission.CALL_PHONEpermission:android.permission.WRITE_CALL_LOGpermission:android.permission.USE_SIPpermission:android.permission.PROCESS_OUTGOING_CALLSpermission:com.android.voicemail.permission.ADD_VOICEMAILgroup:android.permission-group.CALENDARpermission:android.permission.READ_CALENDARpermission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERApermission:android.permission.CAMERAgroup:android.permission-group.SENSORSpermission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATIONpermission:android.permission.ACCESS_FINE_LOCATIONpermission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGEpermission:android.permission.READ_EXTERNAL_STORAGEpermission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONEpermission:android.permission.RECORD_AUDIOgroup:android.permission-group.SMSpermission:android.permission.READ_SMSpermission:android.permission.RECEIVE_WAP_PUSHpermission:android.permission.RECEIVE_MMSpermission:android.permission.RECEIVE_SMSpermission:android.permission.SEND_SMSpermission:android.permission.READ_CELL_BROADCASTS| 日歷 | READ_CALENDAR |
| 日歷 | WRITE_CALENDAR |
| 相機 | CAMERA |
| 聯系人 | READ_CONTACTS |
| 聯系人 | WRITE_CONTACTS |
| 聯系人 | GET_ACCOUNTS |
| 位置 | ACCESS_FINE_LOCATION |
| 位置 | ACCESS_COARSE_LOCATION |
| 麥克風 | RECORD_AUDIO |
| 電話 | READ_PHONE_STATE |
| 電話 | CALL_PHONE |
| 電話 | READ_CALL_LOG |
| 電話 | WRITE_CALL_LOG |
| 電話 | ADD_VOICEMAIL |
| 電話 | USE_SIP |
| 電話 | PROCESS_OUTGOING_CALLS |
| 傳感器 | BODY_SENSORS |
| 短信 | SEND_SMS |
| 短信 | RECEIVE_SMS |
| 短信 | READ_SMS |
| 短信 | RECEIVE_WAP_PUSH |
| 短信 | RECEIVE_MMS |
| 存儲 | READ_EXTERNAL_STORAGE |
| 存儲 | WRITE_EXTERNAL_STORAGE |
解決了權限問題,但是拍照沒法顯示于imageview
package com.example.software_china;import android.Manifest; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.widget.ImageView;import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List;public class MainActivity extends AppCompatActivity {private Button bt_camera;private Button bt_show_imag;private ImageView iv_image;int writeflag = 0;//判斷儲存權限是否獲取private File file;String[] permissions = new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.ACCESS_NETWORK_STATE,Manifest.permission.ACCESS_WIFI_STATE,Manifest.permission.INTERNET};private final int permissionCode = 100;//權限請求碼public void openCamera() {Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());startActivityForResult(intent,100);}public Uri getImageUri() {Uri imageUri;file=new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}String path = file.getPath();if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {imageUri = Uri.fromFile(file);} else {//兼容android7.0 使用共享文件的形式ContentValues contentValues = new ContentValues(1);contentValues.put(MediaStore.Images.Media.DATA, path);imageUri = this.getApplication().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);}return imageUri;}private void checkPermission() {List<String> permissionList = new ArrayList<>();for (int i = 0; i < permissions.length; i++) {if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {permissionList.add(permissions[i]);}}if (permissionList.size() <= 0) {//說明權限都已經通過,可以做你想做的事情去} else {//存在未允許的權限ActivityCompat.requestPermissions(this, permissions, permissionCode);}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//6.0才用動態權限if (Build.VERSION.SDK_INT >= 23) {checkPermission();}setContentView(R.layout.activity_main);bt_camera=(Button) findViewById(R.id.bt_camera);iv_image =(ImageView) findViewById(R.id.iv_image);bt_show_imag =(Button) findViewById(R.id.bt_show_imag);bt_camera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions((Activity) MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);} else {openCamera();}}});bt_show_imag.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(Intent.ACTION_VIEW);intent.setDataAndType(getImageUri(),"image/*");startActivity(intent);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == 100) {if (resultCode == RESULT_OK) {Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(getImageUri()));} catch (FileNotFoundException e) {e.printStackTrace();}iv_image.setImageBitmap(bitmap);// Android 10 使用圖片uri加載iv_image.setImageURI(getImageUri());}}}}原因
因為拍照后圖片太大,沒法直接放在控件imageview中,需要進行壓縮,這里有相應的壓縮代碼
package com.example.software_china;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable;import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream;/*** Tools for handler picture***/ public final class ImageTools {/*** Transfer drawable to bitmap** @param drawable* @return*/public static Bitmap drawableToBitmap(Drawable drawable) {int w = drawable.getIntrinsicWidth();int h = drawable.getIntrinsicHeight();Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888: Bitmap.Config.RGB_565;Bitmap bitmap = Bitmap.createBitmap(w, h, config);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, w, h);drawable.draw(canvas);return bitmap;}/*** Bitmap to drawable** @param bitmap* @return*/public static Drawable bitmapToDrawable(Bitmap bitmap) {return new BitmapDrawable(bitmap);}/*** Input stream to bitmap** @param inputStream* @return* @throws Exception*/public static Bitmap inputStreamToBitmap(InputStream inputStream)throws Exception {return BitmapFactory.decodeStream(inputStream);}/*** Byte transfer to bitmap** @param byteArray* @return*/public static Bitmap byteToBitmap(byte[] byteArray) {if (byteArray.length != 0) {return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);} else {return null;}}/*** Byte transfer to drawable** @param byteArray* @return*/public static Drawable byteToDrawable(byte[] byteArray) {ByteArrayInputStream ins = null;if (byteArray != null) {ins = new ByteArrayInputStream(byteArray);}return Drawable.createFromStream(ins, null);}/*** Bitmap transfer to bytes** @return*/public static byte[] bitmapToBytes(Bitmap bm) {byte[] bytes = null;if (bm != null) {ByteArrayOutputStream baos = new ByteArrayOutputStream();bm.compress(Bitmap.CompressFormat.PNG, 100, baos);bytes = baos.toByteArray();}return bytes;}/*** Drawable transfer to bytes** @param drawable* @return*/public static byte[] drawableToBytes(Drawable drawable) {BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;Bitmap bitmap = bitmapDrawable.getBitmap();byte[] bytes = bitmapToBytes(bitmap);;return bytes;}/*** Base64 to byte[]// */ // public static byte[] base64ToBytes(String base64) throws IOException { // byte[] bytes = Base64.decode(base64); // return bytes; // } // // /** // * Byte[] to base64 // */ // public static String bytesTobase64(byte[] bytes) { // String base64 = Base64.encode(bytes); // return base64; // }/*** Create reflection images** @param bitmap* @return*/public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) {final int reflectionGap = 4;int w = bitmap.getWidth();int h = bitmap.getHeight();Matrix matrix = new Matrix();matrix.preScale(1, -1);Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w,h / 2, matrix, false);Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2),Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmapWithReflection);canvas.drawBitmap(bitmap, 0, 0, null);Paint deafalutPaint = new Paint();canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint);canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null);Paint paint = new Paint();LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,0x00ffffff, Shader.TileMode.CLAMP);paint.setShader(shader);// Set the Transfer mode to be porter duff and destination inpaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));// Draw a rectangle using the paint with our linear gradientcanvas.drawRect(0, h, w, bitmapWithReflection.getHeight()+ reflectionGap, paint);return bitmapWithReflection;}/*** Get rounded corner images** @param bitmap* @param roundPx* 5 10* @return*/public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {int w = bitmap.getWidth();int h = bitmap.getHeight();Bitmap output = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(output);final int color = 0xff424242;final Paint paint = new Paint();final Rect rect = new Rect(0, 0, w, h);final RectF rectF = new RectF(rect);paint.setAntiAlias(true);canvas.drawARGB(0, 0, 0, 0);paint.setColor(color);canvas.drawRoundRect(rectF, roundPx, roundPx, paint);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(bitmap, rect, rect, paint);return output;}/*** 縮小圖片** @param bitmap* @param width* @param height* @return*/public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {int w = bitmap.getWidth();int h = bitmap.getHeight();Matrix matrix = new Matrix();float scaleWidth = ((float) width / w);float scaleHeight = ((float) height / h);matrix.postScale(scaleWidth, scaleHeight);Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);return newbmp;}/*** Resize the drawable* @param drawable* @param w* @param h* @return*/public static Drawable zoomDrawable(Drawable drawable, int w, int h) {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();Bitmap oldbmp = drawableToBitmap(drawable);Matrix matrix = new Matrix();float sx = ((float) w / width);float sy = ((float) h / height);matrix.postScale(sx, sy);Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,matrix, true);return new BitmapDrawable(newbmp);}/*** Get images from SD card by path and the name of image* @param photoName* @return*/public static Bitmap getPhotoFromSDCard(String path,String photoName){Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" +photoName +".png");if (photoBitmap == null) {return null;}else {return photoBitmap;}}/*** Check the SD card* @return*/public static boolean checkSDCardAvailable(){return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);}/*** Get image from SD card by path and the name of image* @return*/public static boolean findPhotoFromSDCard(String path,String photoName){boolean flag = false;if (checkSDCardAvailable()) {File dir = new File(path);if (dir.exists()) {File folders = new File(path);File photoFile[] = folders.listFiles();for (int i = 0; i < photoFile.length; i++) {String fileName = photoFile[i].getName().split("\\.")[0];if (fileName.equals(photoName)) {flag = true;}}}else {flag = false;} // File file = new File(path + "/" + photoName + ".jpg" ); // if (file.exists()) { // flag = true; // }else { // flag = false; // }}else {flag = false;}return flag;}/*** 將圖片保存到本地SD卡* @param photoBitmap* @param photoName* @param path*/public static void savePhotoToSDCard(Bitmap photoBitmap, String path, String photoName){if (checkSDCardAvailable()) {File dir = new File(path);if (!dir.exists()){dir.mkdirs();}File photoFile = new File(path , photoName + ".png");FileOutputStream fileOutputStream = null;try {fileOutputStream = new FileOutputStream(photoFile);if (photoBitmap != null) {if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {fileOutputStream.flush(); // fileOutputStream.close();}}} catch (FileNotFoundException e) {photoFile.delete();e.printStackTrace();} catch (IOException e) {photoFile.delete();e.printStackTrace();} finally{try {fileOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** Delete the image from SD card* @param path* file:///sdcard/temp.jpg*/public static void deleteAllPhoto(String path){if (checkSDCardAvailable()) {File folder = new File(path);File[] files = folder.listFiles();for (int i = 0; i < files.length; i++) {files[i].delete();}}}//刪除上一次截圖的臨時文件,包括圖片路徑和文件名稱public static void deletePhotoAtPathAndName(String path,String fileName){if (checkSDCardAvailable()) {File folder = new File(path);File[] files = folder.listFiles();for (int i = 0; i < files.length; i++) {System.out.println(files[i].getName());if (files[i].getName().equals(fileName)) {files[i].delete();}}}}}誤點拍照后返回程序崩潰:
Bitmap bitmap= BitmapFactory.decodeFile(path);if(bitmap!=null){Bitmap newBitmap=ImageTools.zoomBitmap(bitmap, bitmap.getWidth()/3, bitmap.getHeight()/3);//由于Bitmap內存占用較大,這里需要回收內存,否則會報out of memory異常bitmap.recycle();//將處理過的圖片顯示在界面上,并保存到本地iv_image.setImageBitmap(newBitmap);ImageTools.savePhotoToSDCard(newBitmap, Environment.getExternalStorageDirectory().getAbsolutePath(), String.valueOf(System.currentTimeMillis()));break;}else{break;}原因
誤點后返回時,bitMap是null,然后就進行一系列錯誤代碼的執行,只需要進行一個bitMap判斷即可
誤點相冊后返回程序崩潰:
ContentResolver resolver=getContentResolver();if(data!=null){Uri originUri=data.getData();try {Bitmap bitMap=MediaStore.Images.Media.getBitmap(resolver, originUri);if(bitMap!=null){Bitmap smallMap=ImageTools.zoomBitmap(bitMap, bitMap.getWidth() / 3, bitMap.getHeight() / 3);bitMap.recycle();iv_image.setImageBitmap(smallMap);}} catch (IOException e) {e.printStackTrace();}break;}else{break;}原因
誤點后返回時,data是null,然后就進行一系列錯誤代碼的執行,只需要進行一個data判斷即可
有些型號的手機BitmapFactory.decodeFile獲取Bitmap為空
原因
找相關資料,發現在android 10系統中
需要在文件下AndroidManifest.xml 加上android:requestLegacyExternalStorage = “true” 這個屬性
<application android:requestLegacyExternalStorage = “true”>測試
總結
以上是生活随笔為你收集整理的安卓开发之Intent系统调用系统相机Camera(中软杯项目)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript与DOM编程
- 下一篇: 常用的三种类别的IP地址