日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

安卓开发———打开相机拍照或者打开相册选择照片并显示出来

發布時間:2023/12/8 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 安卓开发———打开相机拍照或者打开相册选择照片并显示出来 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

打開相機

布局代碼

<Buttonandroid:id="@+id/take_photo"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:text="打開相機"/><Buttonandroid:id="@+id/chose_photo"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:text="選擇本地照片"/><ImageViewandroid:id="@+id/picture"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"/>

獲取控件并綁定事件

@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);take_photo=findViewById(R.id.take_photo);chose_photo=findViewById(R.id.chose_photo);picture=findViewById(R.id.picture);take_photo.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {setTake_photo();}});chose_photo.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {setChose_photo();}}); }

啟動照相機

private void setTake_photo(){//創建file對象儲存拍攝到的照片,將圖片命名為output_image.jpg,將他存儲在sd卡的關聯目錄下,調用getExternalCacheDir()//方法可以獲得這個目錄File outputImg=new File(getExternalCacheDir(),"output_image.jpg");try {if (outputImg.exists()){outputImg.delete();}outputImg.createNewFile();}catch (IOException e){e.printStackTrace();}//判斷系統版本,低于7.0會將file對象轉換為uir對象否則調用getUriForFile將file對象轉化為一個封裝過的uir對象//因為7.0開始直接使用本地真實路徑會被認為是不安全的會拋出FileUirExposeption異常,FileProvider是一個//內容提供器會將封裝的uir提供給外部if (Build.VERSION.SDK_INT>=24){imgUri= FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider",outputImg);String adb=imgUri.toString();}else {imgUri=Uri.fromFile(outputImg);}Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");/* 先來說下intent的作用,intent是Android程序中各組件之間進行交互的一種重要方式,一般被用來啟動活動、啟動服務以及發送廣播等;intent在啟動Activity的時候可以傳遞數據,比如說給另一個Activity傳遞數據,那么活動與活動之間是怎樣進行數據傳遞的呢?這時候就需要用到putExtra()方法。intent中提供一系列的putExtra()方法的重載,可以把想要傳遞的數據暫存在intent中,當另一個活動啟動后,再把這些數據從intent緩存中取出即可。putExtra("A", B)方法中,AB為鍵值對,第一個參數為鍵名,第二個參數為鍵對應的值,這個值才是真正要傳遞的數據。*//* 當向intent傳入 MediaStore.EXTRA_OUTPUT參數后,表明這是一個存儲動作。相機拍攝到的圖片會直接存儲到相應路徑,不會緩存在內存中。*///intent.putExtra(MediaStore.EXTRA_OUTPUT,imgUri);指定圖片輸出地址intent.putExtra(MediaStore.EXTRA_OUTPUT,imgUri);startActivityForResult(intent,TAKE_PHOTO); }

調用 startActivityForResult(intent,TAKE_PHOTO);后會回調onActivityResult(int requestCode, int resultCode, @Nullable Intent data)

@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode){case TAKE_PHOTO:/* String adb=imgUri.toString();Log.d("MainActivity","s輸出為:"+adb);*/Log.d("MainActivity","輸出為:"+requestCode);/* 其實可以理解為系統幫你預設好了的標識符,有RESULT_OKRESULT_CANCELEDRESULT_FIRST_USER在調用系統activity時返回時RESULT_CANCELED如字面意思代表取消,RESULT_OK代表成功。*//* 意思是當Activity的啟動模式是singleTask時,這個Activity不會運行在該task任務棧中.并且會馬上收到一個cancel result的信號.這就是原因了.比如Activity A 使用startActivityForResult()跳轉到Activity B中,同時A的啟動模式是SingleTask, 這時一調用startActivityForResult()去跳轉B,A中的onActivityResult()方法會馬上收到一個RESULT_CANCEL(值為0)的resultCode.這樣RESULT_OK是無法被響應的.*/if (resultCode == Activity.RESULT_OK){try {//將拍攝的照片顯示出來/* BitmapFactory.decodeByteArray(byte[] data, int offset, int length)從指定字節數組的offset位置開始,將長度為length的字節數據解析成Bitmap對象BitmapFactory.decodeFile(String path)該方法將指定路徑的圖片轉成Bitmap,BitmapFactory.decodeFile(String path, Options options)該方法使用options的變量信息,將指定路徑的圖片轉成BitmapdecodeResource()可以將/res/drawable/內預先存入的圖片轉換成Bitmap對象decodeStream()方法可以將InputStream對象轉換成Bitmap對象。*/Bitmap bitmap= BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUri));picture.setImageBitmap(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}break;case CHOSE_PHOTO:/* String adb=imgUri.toString();Log.d("MainActivity","s輸出為:"+adb);*/Log.d("MainActivity","輸出為:"+requestCode);if (resultCode == Activity.RESULT_OK){//判斷系統版本,4.4以上系統用這個方法處理圖片if (Build.VERSION.SDK_INT>=19){handleImageOnKiKat(data);}else {handleImageBeforeKiKat(data);}}break;default:break;} }

接下來我們要在Manifest中注冊我們剛剛用到的fileprovider內容提供器

<providerandroid:authorities="com.example.cameraalbumtest.fileprovider"android:name="androidx.core.content.FileProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths"/></provider>

android:authorities="com.example.cameraalbumtest.fileprovider"中的屬性必須與剛才FileProvider.getUriForFile方法中的第二個參數一致。這里引用了@xml/file_paths,創建這個資源文件

<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-path name="my_images" path=""/></paths>

這里path=""為空代表共享整個sd卡

最后為了適配4.4以前版本再添加權限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 到這里啟動相機拍照的功能就實現了。接下來是打開相冊選擇照片

打開相冊選擇照片

private void setChose_photo(){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();} }

打開相冊屬于危險權限,先為他賦予權限,彈出對話框點擊確定之后會調用onRequestPermissionsResult

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();}} }

邏輯很簡單,就是判斷有權限就調用

private void openAlbum() {Intent intent=new Intent("android.intent.action.GET_CONTENT");//選擇相冊 intent.setType(“audio/*”); //選擇音頻 intent.setType(“video/*”); //選擇視頻//這是正常的訪問系統自帶的文件管理器。但是setType只支持單個setType一般是以下這種(以只查看圖片文件為例):intent.setType("image/*");startActivityForResult(intent,CHOSE_PHOTO); }

這個方法會回調onActivityResult前面已經提到過了
接下來就是處理圖片

private void handleImageBeforeKiKat(Intent data) {String imgPath=null;Uri uri=data.getData();if (DocumentsContract.isDocumentUri(this,uri)){//如果是Document類型的uri,則使用Document id處理String docid=DocumentsContract.getDocumentId(uri);/*1、“==”比較兩個變量本身的值,即兩個對象在內存中的首地址。(java中,對象的首地址是它在內存中存放的起始地址,它后面的地址是用來存放它所包含的各個屬性的地址,所以內存中會用多個內存塊來存放對象的各個參數,而通過這個首地址就可以找到該對象,進而可以找到該對象的各個屬性)2、“equals()”比較字符串中所包含的內容是否相同。*//* String s1,s2,s3 = "abc", s4 ="abc" ;s1 = new String("abc");s2 = new String("abc");s1==s2 是 false //兩個變量的內存地址不一樣,也就是說它們指向的對象不 一樣,s1.equals(s2) 是 true //兩個變量的所包含的內容是abc,故相等。*//*uri.getAuthority()返回此URL的權限部分,如果此URL沒有權限,則返回null。*/if ("com.android.providers.media.documents".equals(uri.getAuthority())){String id = docid.split(":")[1];//解析出數字格式的 idString selection = MediaStore.Images.Media._ID + "=" + id;imgPath = 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));imgPath = getImagePath(contentUri, null);}}else if ("content".equalsIgnoreCase(uri.getScheme())){//如果是 content 類型的 uri , 則使用普通方式處理imgPath = getImagePath(uri, null);}else if("file".equalsIgnoreCase(uri.getScheme())){//如果是 file 類型的 Uri,直接獲取圖片路徑即可imgPath = uri.getPath();}displayImage(imgPath);//顯示選中的圖片}private void handleImageOnKiKat(Intent data) {Uri uri = data.getData();String imagePath = getImagePath(uri, null);displayImage(imagePath);} @SuppressLint("Range") 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; }

4.4以上的·版本就會調用第一個函數處理照片,因為選取相冊中的圖片已經不會在返回真實的uir而是一個封裝過的uir
拿到圖片路徑之后再調用displayImage方法將圖片顯示出來

private void displayImage(String imagePath) {if(imagePath != null){Bitmap bitmap = BitmapFactory.decodeFile(imagePath);BitmapCompressUtils bitmapCompressUtils=new BitmapCompressUtils();Bitmap bitmap1=bitmapCompressUtils.zoomImage(bitmap,100,100);picture.setImageBitmap(bitmap1);}else{Toast.makeText(this,"failed to get image", Toast.LENGTH_LONG).show();}}

這里用到了一個壓縮圖片的方法類

/*** Created by l_zp on 2016/1/20.* 這是一個將圖片進行壓縮的工具類*/ public class BitmapCompressUtils {/*** 壓縮圖片** @param bitMap 要壓縮的bitmap對象* @param maxSize 壓縮的大小(kb)不是很準確大約比輸入值大于100k是因為比例決定的* @return*/public static Bitmap imageZoom(Bitmap bitMap, double maxSize) {if (bitMap != null) {//將bitmap放至數組中,意在bitmap的大小(與實際讀取的原文件要大)ByteArrayOutputStream baos = new ByteArrayOutputStream();bitMap.compress(Bitmap.CompressFormat.JPEG, 100, baos);byte[] b = baos.toByteArray();//將字節換成KBdouble mid = b.length / 1024;//判斷bitmap占用空間是否大于允許最大空間 如果大于則壓縮 小于則不壓縮if (mid > maxSize) {//獲取bitmap大小 是允許最大大小的多少倍double i = mid / maxSize;//開始壓縮 此處用到平方根 將寬帶和高度壓縮掉對應的平方根倍 (1.保持刻度和高度和原bitmap比率一致,壓縮后也達到了最大大小占用空間的大小)bitMap = zoomImage(bitMap, bitMap.getWidth() / Math.sqrt(i),bitMap.getHeight() / Math.sqrt(i));}}return bitMap;}/**** 圖片的縮放方法** @param bgimage :源圖片資源* @param newWidth :縮放后寬度* @param newHeight :縮放后高度* @return*/public static Bitmap zoomImage(Bitmap bgimage, double newWidth,double newHeight) {// 獲取這個圖片的寬和高float width = bgimage.getWidth();float height = bgimage.getHeight();// 創建操作圖片用的matrix對象Matrix matrix = new Matrix();// 計算寬高縮放率float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;// 縮放圖片動作matrix.postScale(scaleWidth, scaleHeight);Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,(int) height, matrix, true);return bitmap;}}

這里就實現所有功能了

https://blog.csdn.net/beyond0525/article/details/8939984

總結

以上是生活随笔為你收集整理的安卓开发———打开相机拍照或者打开相册选择照片并显示出来的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。