安卓开发———打开相机拍照或者打开相册选择照片并显示出来
打開相機
布局代碼
<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前面已經提到過了
接下來就是處理圖片
4.4以上的·版本就會調用第一個函數處理照片,因為選取相冊中的圖片已經不會在返回真實的uir而是一個封裝過的uir
拿到圖片路徑之后再調用displayImage方法將圖片顯示出來
這里用到了一個壓縮圖片的方法類
/*** 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
總結
以上是生活随笔為你收集整理的安卓开发———打开相机拍照或者打开相册选择照片并显示出来的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: B/S中的三层架构和MVC设计模型
- 下一篇: 2021年三季度中国生物制品行业A股上市